JDK 5.0의 새로운 기능 Generics 그거/Java2007. 8. 13. 11:01
# Generics
@ 특징
1. Collection 사용시 Type-Safe 한 Collection을 사용할 수 있다.(Compile time type safety)
2. 이전에는 Collection에 어떤 객체든 넣을 수 있었지만, 지정 객체만 넣음으로써
실행시간이 아닌 컴파일 시점에 오류를 미리 체크할 수 있다.
3. Collection 사용시 Casting 작업이 필요 없다.
기존 코드
List myList = new ArrayList();
myList.add(new String("this is a test");
myList.add(new Integer(100));
// 실행 시간에 오류가 체크됨
Integer integer = (Integer)myList.iterator().next();
변경 코드
List<Integer> myList = new ArrayList<Integer>();
// 컴파일 시점에 오류가 체크됨
myList.add(new String("this is a test");
myList.add(new Integer(100));
Integer integer = (Integer)myList.iterator().next();
@ 선언 방법 및 사용 방법
< > 기호를 사용한다.
E : 선언하여 사용할 때 들어가는 실제 데이터 타입
public boolean add(E o) {
....
}
}
String 객체만 담을 수 있는 ArrayList를 만들 경우 아래와 같이 한다.
이 경우 위 선언에서 봤던 E 는 String 이 되며, 위 선언은 아래와 같이 변경된다고 보면 된다.
public boolean add(String o) {
....
}
}
또한, 아래와 같이 특정 부류(?)에 대해서만 적용이 가능한 선언을 할 수도 있다.
/ \
/ \
/ \
Dog Cat
※ Dog, Cat class는 Animal class를 상속받음
위와 같이 클래스가 구성되어 있고, 동물병원에서 현재 병원에 있는 모든 동물들의 목록을 뽑고자 한다면 // 현재 병원에 있는 동물들의 목록 public void printAnimals(ArrayList<Animal> list) {
아래와 같이 하면 된다.
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
for( Animal a : list ) {
System.out.println(a);
}
}
이와 같이 printAnimals() 라는 method에 병원의 동물들의 목록이 들어가있는 animals(ArrayList<Animal>) 객체를 넘겨서
각 동물들의 정보를 찍을 수 있다.
그런데, 병원에 있는 동물들의 목록을 동물별로 따로 뽑고 싶을 경우는 어떻게 해야 될까?
아래와 같이 강아지들만의 목록이 따로 있다고 하면,
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
위에서 정의된 printAnimals(ArrayList<Animal> list) method로는 강아지들 정보만 있는 dogs(ArrayList<Dog>) 객체를 넘겨서
각 강아지에 대한 정보를 찍을 수 없다.
왜냐하면, printAnimals(ArrayList<Animal> list) method는 인자로 ArrayList<Animal>만 받을 수 있도록 되어 있기 때문이다.
그렇다고 해서 printAnimals(ArrayList<Dog> list) method를 추가한다고 해서 해결되지도 않는다.
중복된 method라고 컴파일시 오류가 발생하기 때문이다.
그러면 어떻게 해야 될까? 바로 아래와 같이 와일드카드를 이용해서 generics를 확장시켜야 한다.
public <T extends Animal> void printAnimals(ArrayList<T> list) {
for( Animal a : list ) {
System.out.println(a);
}
}
public void printAnimals(ArrayList<? extends Animal> list) {
for( Animal a : list ) {
System.out.println(a);
}
}
T : 앞에서 말했던 E 와 같은 개념이다.
extends : 확장, 상속, 구현 등의 개념으로써, 간단하게 'T extends Animal' 은 T는 Animal 부류이다(T의 하위 클래스) 라고 생각하면 된다.
public void printAnimals(ArrayList<Dog> list) {
for( Dog a : list ) {
System.out.println(a);
}
}
public void printAnimals(ArrayList<Cat> list) {
for( Cat a : list ) {
System.out.println(a);
}
}
이제 이 메소드에 dogs(ArrayList<Dog>) 객체를 넘겨서 강아지들의 목록을 제대로 찍을 수 있게 됐다.
여기서 한 가지 알아둘 것은 와일드카드를 사용하면 method의 인자로 넘어온 객체에 대해서 수정을 가할 수 없다는 것이다.
즉, 아래와 같이 하면 컴파일시에 오류가 발생한다.
list.add(new Dog());
for( Cat a : list ) {
System.out.println(a);
}
}
이 Generic을 다음과 같이 사용할 수도 있다.
public final class Pair<A,B> {
public final A first;
public final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
}
위와 같이 Pair 라는 class를 정의할 때 generic을 사용하면,
아래와 같이, 비슷한 유형의 class를 여러개 생성하지 않고, collection 처럼 사용할 수 있다.
Pair<File, Boolean> pair2 = new Pair<File, Boolean>(new File("C:\\"), false);
Pair<String, Integer> pair3 = new Pair<String, Integer>("Won", 1000);
팁!
public void doIt(ArrayList<? extends Animal> animals1, ArrayList<? extends Animal> animals2) {
....
}
는 아래와 같이 사용하면 된다.
public <T extends Animal> void doIt(ArrayList<T> animals1, ArrayList<T> animals2) {
....
}
@ 실행 소스
# Animal.java
public abstract class Animal {
pubilc void eat() {
}
}
# Dog.java
public class Dog extends Animal {
public void bark() {
}
}
# Cat.java
public class Cat extends Animal {
public void meow() {
}
}
# TestGenerics1.java
import java.util.ArrayList;
public class TestGenerics2 {
public void go() {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
ArrayList<Dog> dogs = new ArrayList<Dog>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
takeAnimals(animals);
takeAnimals(dogs);
}
// public void takeAnimals(ArrayList<? extends Animal> animals) {
public <T extends Animal> void takeAnimals(ArrayList<T> animals) {
// wildcard를 사용하면 아래처럼 method 매개변수에 의해 참조되는 목록에 손상이 갈 만한 작업을 할 수 없습니다.
// animals.add(new Dog());
for(Animal a: animals ) {
a.eat();
}
}
public static void main(String[] args) {
new TestGenerics2().go();
}
}
'그거 > Java' 카테고리의 다른 글
Java Anti-Pattern (2) | 2007.08.20 |
---|---|
JDK 5.0의 새로운 기능 Annotation (0) | 2007.08.14 |
java Collection 들 (0) | 2007.08.10 |
객체의 hashcode에 대한 고찰 (0) | 2007.08.09 |
The Factory Method Pattern - Design Patterns in Java - (1) | 2007.05.30 |