"제네릭 (Generic)"
: 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법
- 인스턴스를 사용할 때 데이터 타입을 확정함
- 매개변수와 비슷하게 동작함
- 변수의 데이터 타입과 관련이 있음
class Person<T> {
public T info;
Person(T info) { this.info = info; }
}
// 제네릭화 하지 않고 info의 데이터 타입을 Object로 지정하면, info에 어떠한 타입이 들어가도 컴파일 오류가 나지 않음 (타입이 안전하지 않음)
public class GenericDemo {
public static void main(String[] args) {
Person<String> p1 = new person<String>();
Person<StringBuilder> p2 = new person<StringBuilder>();
// p1, p2의 차이는 각각의 info의 데이터 타입이 String인지 StringBuilder인지의 차이임
}
}
- 컴파일 단계에서 오류가 검출됨
- 중복의 제거와 타입 안전성을 동시에 추구함
class StudentInfo {
public int grade;
StudentInfo(int grade) { this.grade = grade; }
}
class EmployeeInfo{
public int rank;
EmployeeInfo(int rank) { this.rank = rank; }
}
class Person<T> {
public T info;
Person(T info) { this.info = info; }
}
public class GenericDemo {
public static void main(String[] args) {
Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
EmployeeInfo ei1 = p1.info;
System.out.println(ei1.rank); // 1
Person<String> p2 = new Person<String>("부장");
String ei2 = p2.info;
System.out.println(ei2.rank); // 컴파일 실패
// p2.info가 String이고 String은 rank 필드가 없는데 이것을 호출하고 있기 때문에 컴파일에 실패함
}
}
- 제네릭 데이터 타입에는 기본 데이터 타입이 아닌, 참조형 데이터 타입만 올 수 있음
class Person<T, S> {
public T info;
public S id;
Person(T info, S id){
this.info = info;
this.id = id;
}
}
// 복수의 제네릭
public class GenericDemo {
public static void main(String[] args) {
Person<EmployeeInfo, int> p1 = new Person<EmployeeInfo, int>(new EmployeeInfo(1), 1);
// 제네릭 데이터 타입에는 참조형 데이터 타입만 올 수 있음
}
}
- "wrapper 클래스" : 자바에서 제공하는 클래스로, 기본 데이터 타입을 참조 데이터 타입으로 변환
- wrapper 클래스를 사용하면 기본 데이터 타입을 사용할 수 있음
class EmployeeInfo {
public int rank;
EmployeeInfo(int rank) { this.rank = rank; }
}
class Person<T, S> {
public T info;
public S id;
Person(T info, S id){
this.info = info;
this.id = id;
}
}
public class GenericDemo {
public static void main(String[] args) {
EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
System.out.println(p1.id.intValue());
}
}
- intValue( ) : Integer 객체에서 int형 값을 추출
- 제네릭은 생략이 가능함
EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
Person p2 = new Person(e, i);
// 제네릭 생략
class Person<T, S> {
public T info;
public S id;
Person(T info, S id){
this.info = info;
this.id = id;
}
public <U> void printInfo(U info){
System.out.println(info);
}
// 제네릭은 메소드에 적용할 수도 있음
}
public class GenericDemo {
public static void main(String[] args) {
EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
p1.<EmployeeInfo>printInfo(e);
p1.printInfo(e);
}
}
- extends로 제네릭으로 올 수 있는 데이터 타입을, 특정 클래스나 인터페이스의 하위로 제한할 수 있음
class Person<T extends Info> {
// Info의 하위 클래스만 타입으로 받겠다는 뜻임
public T info;
Person(T info) { this.info = info; }
}
public class GenericDemo {
public static void main(String[] args) {
Person p1 = new Person(new EmployeeInfo(1));
Person<String> p2 = new Person<String>("부장"); // 에러
// String은 Info의 하위 클래스가 아니기 때문임
}
}
interface Info {
int getLevel();
}
class EmployeeInfo implements Info {
public int rank;
EmployeeInfo(int rank) { this.rank = rank; }
public int getLevel() {
return this.rank;
}
}
class Person<T extends Info> {
// 제네릭 데이터 타입을 특정 인터페이스의 하위로 제한할 수 있음
public T info;
Person(T info) { this.info = info; }
}
public class GenericDemo {
public static void main(String[] args) {
Person p1 = new Person(new EmployeeInfo(1));
Person<String> p2 = new Person<String>("부장");
}
}
- super는 상위를 제한
(extends와 반대)
class Person<T> {
public T info;
Person(T info) {
this.info = info;
info.getLevel(); // 에러
// <T>는 <T extends Object>와 같기 때문에 toString() 등 Object가 기본으로 제공하는 메소드만 사용할 수 있음
}
}
'onYouTube > Java' 카테고리의 다른 글
Collections Framework (0) | 2021.03.27 |
---|---|
참조 (0) | 2021.03.27 |
상수와 enum (0) | 2021.03.27 |
Object 클래스 (0) | 2021.03.26 |
예외 (0) | 2021.03.26 |