[JAVA] 제네릭 (Generic)

진예·2023년 10월 2일
0

JAVA

목록 보기
2/10
post-thumbnail

💡 제네릭 (Generic)

사용될 데이터 타입을 클래스 정의 시 미리 명시하지 않고, 객체 생성 시 명시하여 사용하는 기법


📒 일반 클래스

📝 특정 데이터 타입

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 타입의 변수를 선언해야 한다!

📝 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 타입으로 저장 가능
Object o = nc.getData(); // 가장 마지막에 저장된 "홍길동"이 저장됨.

  • Object 타입 ➡️ 실제 데이터 타입으로 변환하는 경우, 잘못된 타입 변환으로 인해 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
}

📒 주의사항

  1. static 멤버 내에서 제네릭 타입 파라미터 사용 불가 : static 멤버는 인스턴스 생성 시점보다 먼저 메모리에 로딩되므로 타입 변경 불가능

  2. 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) {};
		
	}
}
profile
백엔드 개발자👩🏻‍💻가 되고 싶다

0개의 댓글