///////
Search

제네릭_이연재

1. 제네릭

1. 제네릭의 이해

제네릭 이전 코드의 문제점(1)

class Apple{ @Override public String toString() { return "나는 사과입니다."; } } class Orange{ @Override public String toString() { return "나는 오렌지입니다."; } } class Box{ private Object obj; public void set(Object obj) { this.obj = obj; } public Object get() { return obj; } } public class testGeneric { 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); } }
Plain Text
복사
위 코드에서 처럼 Object 클래스를 사용할 경우 어쩔 수 없이 형 변환 과정이 수반된다.
또한 컴파일 과정에서 실수가 발견되지 않을 수 있다.

제네릭 이전 코드의 문제점(2)

public static void main(String[] args){ Box aBox = new Box(); Box oBox = new Box(); // 다음 두 문장은 프로그래머의 실수이다. aBox.set("Apple"); oBox.set("Orange"); System.out.println(aBox.get()); System.out.println(oBox.get()); }
Plain Text
복사
위 코드는 프로그래머가 실수를 해도 제대로 출력이 되기 때문에 더욱 문제가 크다.
object에서 모든 함수를 받아버려서 생기는 문제이다.
따라서 이러한 문제를 해결하기 위해 제네릭 클래스가 나타나게 되었다.

2. 제네릭 클래스란

제네릭 클래스란 클래스 내부에서 타입을 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다.
예제) 제네릭 클래스(1)
class Box<T> { private T obj; public void set(T obj) { this.obj = obj; } public T get() { return obj; } } public class testGeneric2 { public static void main(String[] args) { //T자리에 Apple이 들어가 인스턴스를 생성. //Apple 또는 Apple을 상속하는 하위 클래스의 인스턴스를 저장할 수 있다. Box<Apple> aBox = new Box<Apple>(); Box<Orange> oBox = new Box<Orange>(); aBox.set(new Apple()); //사과를 상자에 담는다. oBox.set(new Orange()); //오렌지를 상자에 담는다. // aBox.set("apple"); ->Object쓸때는 안났는데 제네릭에선 컴파일 에러가남. Apple ap = aBox.get(); //사과를 꺼내는데 형 변환 하지 않는다. Orange og = oBox.get(); //오렌지를 꺼내는데 형 변환 하지 않는다. System.out.println(ap); System.out.println(og); Box<String> sBox = new Box<>(); sBox.set("스트링"); System.out.println(sBox.get()); } }
Plain Text
복사
//실행 결과 나는 사과입니다. 나는 오렌지입니다. 스트링
Plain Text
복사
위 예제 처럼 제네릭 문법을 쓰면 컴파일시 타입이 이미 결정되어 진다.
타입 매개변수: Box<T>에서 T
타입 인자: Box<Apple>에서 Apple
매개변수화 타입: Box<Apple>
예제) 제네릭 클래스(2)
class DBox<L,R>{ private L left; private R right; public void set(L left, R right) { this.left = left; this.right = right; } @Override public String toString() { return left + "&" + right; } } public class testGeneric3 { public static void main(String[] args) { DBox<String, Integer> box = new DBox<String, Integer>(); //DBox<String, Integer> box = new DBox<>(); ->뒤에 생략 가능 box.set("Apple", 25); System.out.println(box); DBox<String, Integer> box2 = new DBox<String, Integer>(); box2.set("Orange", 28); System.out.println(box2); } }
Plain Text
복사
//실행 결과 Apple&25 Orange&28
Plain Text
복사
위의 코드처럼 두개의 타입을 지정해 줄수도 있다.

3. 제네릭 클래스의 타입 인자 제한하기

타입 인자 제한

class Box<T extends Number>{ //인스턴스 생성 시 타입 인자로 Number 또는 이를 상송하는 클래스만 올수 있음. private T ab; 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); ... }
Plain Text
복사
위 예제에서 처럼 기본적으로 Integer와 Double이 Number를 상속받고 있으므로 사용 할 수 있다.

타입 인자 제한의 효과

상속받은 클래스의 메소드를 사용하기 위해 타입 인자를 제한한다.
예제) 타입 인자를 제한하지 않았을때
class Box<T>{ private T ob; ... public int toIntValue(){ return ob.intValue(); //컴파일 에러 } }
Plain Text
복사
위 예제는 intValue가 타입인자를 제한하지 않았기 때문에 intValue를 사용할 수 없다.
intValue를 사용하기 위해선 Number클래스로 타입 인자를 제한해야 한다.
예제) 타입 인자를 제한했을 때
class Box<T extends Number>{ private T ob; ... public int toIntValue(){ return ob.intValue(); } }
Plain Text
복사
위 예제는 Number의 안에 있는 intValue()를 사용하기 때문에 에러가 나지 않는다.