사용될 데이터 타입을 클래스 정의 시 미리 명시하지 않고, 객체 생성 시 명시하여 사용하는 기법
✅ NormalIntegerClass : 정수형 데이터만 저장 가능
class NormalIntegerClass {
int data; // data 변수에는 정수형 데이터만 저장 가능
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
...
NormalIntegerClass nic = new NormalIntegerClass();
nic.data = 10; // 정수 저장 가능
// nic.data = 3.14; // 실수 저장 불가능
// nic.data = "홍길동"; // 문자열 저장 불가능
✏️ : 한 변수에 여러 타입의 데이터를 저장하려면 최소 Object
타입의 변수를 선언해야 한다!
✅ NormalObjectClass : 모든 데이터타입 저장 가능➡️ Object 타입으로 업캐스팅
class NormalObjectClass {
Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
...
NormalObjectClass nc = new NormalObjectClass();
nc.setData(1); // 정수형 데이터
nc.setData(3.14); // 실수형 데이터
nc.setData("홍길동"); // 문자열 데이터
Object o = nc.getData(); // 가장 마지막에 저장된 "홍길동"이 저장됨.
ClassCastException
이 발생할 수 있다!String data1 = (String)o;
// int data2 = (int)o; // 예외 발생!
✏️ : data2
의 경우, o
에는 문자열 데이터가 저장되어 있기 때문에 정수형으로 변환할 수 없어 ClassCastException
(형변환 예외) 발생!
클래스명 뒤에
<>
기호를 사용하여 가상의 자료형(주로 E 또는 T) 명시➡️ 클래스 내에서 데이터타입 대신 제네릭 타입을 데이터 타입으로 지정 가능!
✅ GenericClass : 가상의 자료형 T를 데이터 타입으로 지정
class GenericClass<T> {
T member; // 멤버변수 member의 데이터타입 : T (실제 데이터타입 X)
public T getMember() {
return member;
}
public void setMember(T member) {
this.member = member;
}
}
객체 생성 시, 클래스명 뒤 제네릭 타입 자리에 사용할 데이터 타입을 참조 데이터타입 형식으로 명시 (Integer, Character, ...)
1. 기본 자료형 지정 : T
➡️ Integer
GenericClass<Integer> gc = new GenericClass<Integer>();
gc.setMember(1); // 정수형 데이터 저장 가능
// gc.setMember("홍길동"); // 문자열 데이터 저장 불가능
int num = gc.getMember();
2. 클래스 타입 지정 : T
➡️ Person
public class Person {
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
...
Person p = new Person("홍길동", 20);
GenericClass<Person> gc4 = new GenericClass<Person>();
gc4.setMember(p); // Person 타입 저장 가능
System.out.println(gc4.getMember());
3. 제네릭 타입을 지정하지 않는 경우 : T
➡️ Object
GenericClass gc5 = new GenericClass();
gc5.setMember(1); // 정수형 저장 가능
gc5.setMember("홍길동"); // 문자열 저장 가능
gc5.setMember(new Person("홍길동", 20)); // Person 타입 저장 가능
✏️ : 제네릭 타입을 명시하지 않으면 Object 타입으로 지정되어 모든 데이터 타입을 다룰 수 있다!
슈퍼클래스에 제네릭 타입이 지정되어 있는 경우, 서브클래스에서 상속받을 때 부모의 타입 파라미터를 서브클래스 타입 파라미터로 명시해야 함.
class Class1<P> {}
interface Interface<Q> {}
class SubClass<P, Q, R> extends Class1<P> implements Interface1<Q> {
P var1; // 슈퍼클래스 Class1의 타입 P
Q var2; // 슈퍼클래스 Interfacle1의 타입 Q
R var3; // 자신의 타입 R
}
static
멤버 내에서 제네릭 타입 파라미터 사용 불가 :static
멤버는 인스턴스 생성 시점보다 먼저 메모리에 로딩되므로 타입 변경 불가능
new / instanceof
연산자 사용 시 제네릭 타입 파라미터 사용 불가 : 컴파일 시점에서 생성자 타입 / T의 데이터타입이 확인 불가능하므로 사용 불가능
class GenericClass2<T> {
// private static T staticMember;
// T instance = new T();
public void compare() {
Object o = new Object();
// if(o instanceof T) {};
}
}