달력

11

« 2024/11 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
2007. 8. 13. 11:01

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 class ArrayList<E> extends AbstractList<E> {
      public boolean add(E o) {
          ....
      }
  }

  String 객체만 담을 수 있는 ArrayList를 만들 경우 아래와 같이 한다.

  List<String> arrayList = new ArrayList<String>();

  이 경우 위 선언에서 봤던 E 는 String 이 되며, 위 선언은 아래와 같이 변경된다고 보면 된다.

  public class ArrayList<String> extends AbstractList<String> {
        public boolean add(String o) {
             ....
        }
  }

  또한, 아래와 같이 특정 부류(?)에 대해서만 적용이 가능한 선언을 할 수도 있다.

                                 Animal
                                  / \
                                 /   \
                                /     \
                              Dog      Cat

※ Dog, Cat class는 Animal class를 상속받음

  위와 같이 클래스가 구성되어 있고, 동물병원에서 현재 병원에 있는 모든 동물들의 목록을 뽑고자 한다면
  아래와 같이 하면 된다.

  // 현재 병원에 있는 동물들의 목록
  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());

  public void printAnimals(ArrayList<Animal> list) {
      for( Animal a : list ) {
          System.out.println(a);
      }
  }

  이와 같이 printAnimals() 라는 method에 병원의 동물들의 목록이 들어가있는 animals(ArrayList<Animal>) 객체를 넘겨서
  각 동물들의 정보를 찍을 수 있다.

  그런데, 병원에 있는 동물들의 목록을 동물별로 따로 뽑고 싶을 경우는 어떻게 해야 될까?
  아래와 같이 강아지들만의 목록이 따로 있다고 하면,

  List<Dog> dogs = new ArrayList<Dog>();
  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의 인자로 넘어온 객체에 대해서 수정을 가할 수 없다는 것이다.

  즉, 아래와 같이 하면 컴파일시에 오류가 발생한다.

  public void printAnimals(ArrayList<Cat> list) {
      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<String, String> pair1 = new Pair<String, String>("Hello", "World");
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
:
Posted by 뽀기