1. 제네릭이란?
어떤 값이 하나의 참조 자료형이 아닌 여러 참조 자료형을 사용할 수 있도록 프로그래밍하는 것을 '제네릭(Generic) 프로그래밍' 이라고 한다.
2. 제네릭의 필요성
어떤 변수가 여러 참조 자료형을 사용할 수 있도록 Object 클래스를 사용하면 다시 원래 자료형으로 반환해 주기 위해 매번 형 변환을 해야하는 번거로움이 있다.
Public class ThreeDPrinter{
private Object material;
public void setMaterial(Object material) {
this.material = material;
}
public Object getMaterial() {
return material;
}
}
ThreeDPrinter printer = new ThreeDPrinter();
Powder p1 = new Powder();
// 자동 형 변환됨
printer.setMaterial(p1);
// 직접 형변환 해야함
Powder p2 = (Powder)printer.getMaterial();
이러한 경우, 여러 참조 자료형이 쓰일 수 있는 곳에 특정한 자료형을 지정하지 않고 클래스나 메서드를 정의한 후 사용하는 시점에 어떤 자료형을 사용할 것인지 지정하는 방식인 제네릭 프로그래밍 방식을 사용한다.
3. 제네릭 클래스 정의하기
제네릭에서는 여러 참조 자료형을 사용해야 하는 부분에 Object 가 아닌 하나의 문자로 표현한다.
// 제네릭 클래스
Public class GenericPrinter<T> {
private T material;
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
}
여러 참조 자료형을 사용해야하는 부분에 기존에는 Object를 썼지만 T로 바꿔썼다.
T를 자료형 매개변수라고 부른다. 클래스 이름을 GenericPrinter<T>로 정의하고 클래스를 사용할 때 T 위치에 실제 사용할 자료형을 지정한다.
1. 다이아몬드 연산자<>
자바 7부터는 제네릭 자료형의 클래스를 생성할 때 생성자에 사용하는 자료형(<> 안에 자료형)을 생략할 수 있다. 여기서 <>를 다이아몬드 연산자라고 한다.
ArrayList<String> list = new ArrayList<> ();
2. 자료형 매개변수 T와 static
static 변수나 메서드는 인스턴스 생성 전에 생성되고 T의 자료형은 제네릭 클래스의 인스턴스가 생성될 때 정해진다. 따라서 static 변수/메서드의 생성은 T의 자료형이 결정되는 시점보다 빠르기 때문에 static 변수의 자료형이나 static 메서드 내부 변수의 자료형으로 T를 사용할 수 없다!
(참고) 자료형 매개변수로 T 외의 다른 문자도 사용가능하다. E는 element, K는 key, V는 value를 의미한다.
3. 제네릭에서 자료형 추론하기
자바 10부터는 지역 변수에 한해서 자료형을 추론할 수 있다.
ArrayList<String> list = new ArrayList<String>();
// 제네릭에서 자료형 추론하기
var list = new ARrayList<String>();
4. 제네릭 클래스 사용하기
제네릭을 사용하면 컴파일러가 자료형을 확인해주기 때문에 안정적이면서 형 변환 코드가 줄어든다.
GenericPrinter<Powder> | 제네릭 자료형, 매개변수화된 자료형 |
Powder | 대입된 자료형 |
1. 제네릭 클래스 사용 예제
1) Powder 클래스, Plastic 클래스 정의하기
재료로 사용할 Powder, Plastic
2) GenericPrinter<T> 클래스 정의하기
Power, Plastic 재료로 모형을 출력하는 프린터를 제네릭 클래스로 정의
- GenericPrinter<T> 클래스의 인스턴스 변수 material은 자료형 매개변수 T로 선언
- getMateiral() 은 T 자료형 변수 material 반환
메서드 선언부나 메서드의 매개변수로 자료형 매개변수 T를 사용한 메서드를 '제네릭 메서드'라고 한다.
3) GnericPrinter<T> 클래스 사용하기
GneericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();
- 사용할 참조 자료형(Powdr, Plastic 등) 을 지정하여 GenericPrinter 클래스 생성
2. 제네릭에서 대입된 자료형을 명시하지 않는 경우
제네릭에서 대입된 자료형을 명시하지 않는 경우, 컴파일 오류는 아니지만 컴파일러가 어떤 자료형을 사용할 것인지 알 수 없어 getMaterial() 메서드에서 강제로 형 변환을 해야한다.
따라서 제네릭 클래스를 사용하는 경우, 대입된 자료형으로 사용할 참조 자료형을 지정하는 것이 좋다.
5. T 자료형에 사용할 자료형을 제한하는 <T extends 클래스>
제네릭 클래스에서 T 자료형에 사용할 자료형에 제한을 둘 수 있다.
사용할 클래스에 자료형 제한을 두는 방식으로 extends 예약어를 사용한다.
T에 대입된 자료형으로 사용할 클래스를 아래와 같이 추상 클래스에서 상속받는다.
1) Material 추상 클래스 정의하기
2) Powder클래스, Plastic 클래스 Material 추상 클래스 상속받기
3) GnericPrinter<T extends Material>
public class GenericPrinter<T extends Material> {
private T material;
...
}
- Material을 상속받은 클래스만 T 자료형에 대입될 수 있도록 제한을 둔다.
1. <T extends 클래스> 로 상위 클래스 메서드 사용하기
1) <T>
T는 컴파일할 때 Object 클래스로 변환된다. 그래서 extends를 하지 않고 <T>로 사용하는 경우, Object 클래스가 기본으로 제공하는 메서드만 사용할 수 있다.
public class GenericPrinter<T> {
private T material;
}
2) <T extends 클래스>
상속한 상위 클래스에서 선언하거나 구현한 메서드를 모두 사용할 수 있다. 실제로 <T extends Material>를 사용하면 컴파일할 때 T 자료형이 Object가 아닌 Material 로 변환된다.
public class GenericPrinter<T extends Material> {
private T material;
}
6. 제네릭 메서드 활용하기
제네릭 클래스가 아닌 일반 클래스에서도 내부에 제네릭 메서드를 구현할 수 있다.
7. 컬렉션 프레임워크에서 사용하는 제네릭
'Java > Do It! 자바 프로그래밍' 카테고리의 다른 글
[JAVA] 12-3.컬렉션 프레임워크_List 인터페이스 (0) | 2022.05.09 |
---|---|
[JAVA] 12-2.컬렌션 프레임워크_컬렉션 프레임워크 (0) | 2022.05.09 |
[JAVA] 11-4. 기본 클래스_Class 클래스 (0) | 2022.05.08 |
[JAVA] 11-3. 기본 클래스_Wrapper 클래스 (0) | 2022.05.08 |
[JAVA] 11-2. 기본 클래스_String 클래스 (0) | 2022.05.07 |