다중 매개변수 기반 제네릭 클래스의 정의
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;
}
}
public static void main(String[] args) {
DBox<String, Integer> box = new DBox<String, Integer>();
box.set("Apple", 25);
System.out.println(box);
}
타입 매개변수의 이름 규칙
일반적인 관례
한 문자로 이름을 짓는다.
대문자로 이름을 짓는다.
보편적인 선택
E Element
K Key
N Number
T Type
V Value
기본 자료형에 대한 제한 그리고 래퍼 클래스
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<int> box = new Box<int>();
-> 타입 인자로 기본 자료형이 올 수 없으므로 컴파일 오류 발생
다이아몬드 기호 <>
따라서 다음 문장을 대신하여,
Box<Apple> aBox = new Box<Apple>();
다음과 같이 쓸 수 있다.
Box<Apple> aBox = new Box<>();
참조변수 선언을 통해서 컴파일러가 사이에 Apple이 와야 함을 유추한다.
'매개변수화 타입'을 '타입 인자'로 전달
class Box<T> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
public static void main(String[] args) {
Box<String> sBox = new Box<>();
sBox.set("I am so happy.");
Box<Box<String>> wBox = new Box<>();
wBox.set(sBox);
Box<Box<Box<String>>> zBox = new Box<>();
zBox.set(wBox);
System.out.println(zBox.get().get().get());
}
제네릭 클래스의 타입 인자 제한하기
class Box<T extends number> { ... }
-> 인스턴스 생성 시 타입 인자로 Number 또는 이를 상속하는 클래스만 올 수 있음
class Box<T extends Number> {
private T ob;
public void set(T o) {
ob = o;
}
public T get() {
return ob;
}
}
public static void main(String[] args) {
Box<Integer> iBox = new Box<>();
iBox.set(24);
Box<Double> dBox = new Box<>();
dBox.set(5.97);
. . . .
}
타입 인자 제한의 효과
class Box<T> {
private T ob;
. . . .
public int toIntValue() {
return ob.intValue(); // ERROR! - 컴파일 에러 발생!! - T 가 String 일 수도 있기 때문
}
}
class Box<T extends Number> {
private T ob;
. . . .
public int toIntValue() {
return ob.intValue(); // OK!
}
}
이 효과가 타입 인자를 제한하는 실질적인 이유인 경우가 많다.(중요!!!!!!)
제네릭 클래스의 타입 인자를 인터페이스로 제한하기
interface Eatable { public String eat(); }
class Apple implements Eatable {
public String eat() {
return "It tastes so good!";
}
. . . .
}
class Box<T extends Eatable> {
T ob;
public void set(T o) { ob = o; }
public T get() {
System.out.println(ob.eat()); // Eatable로 제한하였기에 eat 호출 가능
return ob;
}
}
하나의 클래스와 하나의 인터페이스에 대해 동시 제한 가능!!
class Box<T extends Number & Eatable> { ... }
Number는 클래스 이름 Eatable은 인터페이스 이름
제네릭 메소드의 정의
클래스 전부가 아닌 메소드 하나에 대해 제네릭으로 정의
class BoxFactory {
public static <T> Box<T> makeBox(T o) {
Box<T> box = new Box<T>(); // 상자를 생성하고,
box.set(o); // 전달된 인스턴스를 상자에 담아서,
return box; // 상자를 반환한다.
}
}
제네릭 메소드의 T는 메소드 호출 시점에 결정한다.
Box<String> sBox = BoxFactory.<String>makeBox("Sweet");
Box<Double> dBox = BoxFactory.<Double>makeBox(7.59); // 7.59에 대해 오토 박싱 진행됨
다음과 같이 타입 인자 생략 가능
Box<String> sBox = BoxFactory.makeBox("Sweet");
Box<Double> dBox = BoxFactory.makeBox(7.59); // 7.59에 대해 오토 박싱 진행됨
제네릭 메소드의 제한된 타입 매개변수 선언
// <T extends Number>는 타입 인자를 Number를 상속하는 클래스로 제한함을 의미
public static <T extends Number> Box<T> makeBox(T o) {
. . . .
// 타입 인자 제한으로 intValue 호출 가능
System.out.println("Boxed data : " + o.intValule());
return box;
}
// 타입 인자를 Number를 상속하는 클래스로 제한
public static <T extends Number> T openBox(Box<T> box) {
// 타입 인자 제한으로 intValue 호출 가능
System.out.println("Unboxed data : " + box.get().intValue());
return box.get();
}
'# 02 > Java' 카테고리의 다른 글
[윤성우 열혈자바] 23-1. 컬렉션 프레임워크의 이해 (0) | 2019.10.24 |
---|---|
[윤성우 열혈자바] 22-1. 제네릭의 심화 문법 (0) | 2019.10.23 |
[윤성우 열혈자바] 21-1. 제네릭의 이해 (0) | 2019.10.23 |
[윤성우 열혈자바] 20-4. Arrays 클래스 (0) | 2019.10.23 |
[윤성우 열혈자바] 20-3. Math 클래스와 난수의 생성, 그리고 문자열 토큰의 구분 (0) | 2019.10.23 |