도찐개찐
[JAVA] 제네릭스(Generics) 본문
제네릭의 이해
🤔 제네릭?
제네릭이 갖는 의미는 일반화이다. 여기서 일반화의 대상은 자료형이다.
제네릭이 등장하면서 자료형에 의존적이지 않은 클래스를 정의할 수 있게 되었다.
제네릭을 쓰는 이유
class Apple {
public String toString() {
return "I am an apple.";
}
}
class Orange {
public String toString() {
return "I am an orange.";
}
}
class Box {
private Object ob;
public void set(Object o) {
ob = o;
}
public Object get() {
return ob;
}
}
class FruitAndBox2 {
public static void main(String[] args) {
Box aBox = new Box();
Box oBox = new Box();
// 상자에 과일을 담는다.
aBox.set(new Apple());
oBox.set(new Orange());
// 상자에서 과일을 꺼낸다.
Apple ap = (Apple)aBox.get();
Orange og = (Orange)oBox.get();
System.out.println(ap);
System.out.println(og);
}
}
위의 코드에서 Box 내에서 인스턴스를 저장하는 참조변수가 Object이기 때문에 내용물을 꺼낼 때는 형 변환이 필요하다.
또는 담은 자료형과 꺼내는 자료형이 다르다면 컴파일 에러가 난다.
제네릭을 사용하지 않는다면,
- 필요시 형 변환을 해야 한다.
- 자료형과 관련된 프로그래머의 실수가 컴파일 과정에서 드러나지 않는다.
제네릭 기반 클래스 정의하기
위의 Box 클래스를 변경해본다.
class Box<T> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
T 는 인스턴스를 생성할 때 결정하면 된다.
인스턴스 생성 시 T의 자료형을 결정하는 것이 '제네릭'이다.
제네릭 기반 클래스의 인스턴스 생성
Box<Apple> aBax = new Box<Apple>();
- T를 Apple로 결정하여 인스턴스 생성.
- 따라서 Apple 또는 Apple을 상속하는 하위 클래스의 인스턴스 저장 가능.
타입 매개변수
Box<T> 에서 T
타입 인자
Box<Apple>에서 Apple
매개변수화 타입 = 제네릭 타입
Box<Apple>
제네릭의 기본 문법
다중 매개변수 기반 클래스의 정의
칸이 둘로 나뉘어 진 상자를 표현한 제네릭 클래스 정의이다.
class DBox<L, R> {
private L left; // 왼쪽 수납 공간
private R right; // 오른쪽 수납 공간
public void set(L o, R r) {
left = o;
right = r;
}
@Override
public String toString() {
return left + " & " +right;
}
}
class MultiTypeParam {
public static void main(String[] args) {
DBox<String, Integer> box = new DBox<String, Integer>();
box.set("Apple", 25);
System.out.println(box);
}
}
타입 매개변수의 규칙
- 한 문자로 이름을 짓는다.
- 대문자로 이름을 짓는다.
기본 자료형에 대한 제한
매개변수화 타입을 구성할 때 기본 자료형의 이름은 타입 인자로 쓸 수 없다.
하지만 기본 자료형에 대한 래퍼 클래스가 존재하고, 필요 상황에서 박싱과 언박싱이 자동으로 이뤄지니,
다음과 같이 정의할 수 있다.
class Box<T> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
class PrimitivesAndGeneric {
public static void main(String[] args) {
Box<Integer> iBox = new Box<Integer>();
iBox.set(125);
int num = iBox.get();
System.out.println(num);
}
}
타입 인자의 생략
다이아몬드 기호
컴파일러는 제네릭 관련 문장에서 자료형의 이름을 추론하는 능력을 가지고 있다.
따라서
Box<Apple> aBox = new Box<Apple>(); 를 Box<Apple> aBox = new Box<>(); 와 같이 쓸 수 있다.
타입 인자 제한하기
Box<T> 에는 무엇이든 담을 수 있었지만, 클래스는 그 특성과 용도가 있으니 자료형을 제한할 수 있어야 한다.
이때 extends 를 사용해 타입 인자를 제한한다.
class Box<T extends Number> {...}
- 인스턴스 생성 시 타입 인자로 Number 또는 이를 상속하는 클래스만 올 수 있다.
제네릭 메소드의 정의
클래스 뿐만 아니라 일부 메소드에 대해서만 제네릭으로 정의하는 것도 가능하다.
static 선언의 유무에 상관없이 제네릭 메소드의 정의가 가능하다.
public static <T> Box<T> makeBox(T o) {...}
- 메소드의 이름은 makeBox이고, 반환형은 Box<T>이다.
- static과 Box<T> 사이에 위치한 <T>는 T가 타입 매개변수임을 알리는 표시다.
'JAVA' 카테고리의 다른 글
[JAVA] 람다식(Lambda) (0) | 2022.07.07 |
---|---|
[JAVA] 중첩클래스(Nested Class) (0) | 2022.07.07 |
[JAVA] 다형성(polymorphism) (0) | 2022.07.07 |
[JAVA] instanceof (0) | 2022.07.07 |
[JAVA] 클래스 형변환 (0) | 2022.07.07 |