J2SE 5.0(자바 2 플랫폼, 스탠다드 에디션 5.0)에서는 자바 프로그래밍 언어와 플랫폼에 Generics를 도입했습니다. 가장 단순하고 일반적인 사용의 예로, Generics는 컬렉션에 무엇을 저장할 것인지 식별할 수 있게 해줍니다. 따라서 프로그램에 ObjectsList가 있다고 말하지 않고, String 개체 또는 다른 클래스 유형의 List가 있다고 지정할 수 있습니다. 그러면 실수로 잘못된 유형을 List에 추가하더라도 컴파일러에서 이 오류를 알려 줍니다. 즉 프로그램을 실행하고 fetch 연산에 의해 런타임 캐스팅 예외가 발생하는 코드 지점에 프로그램이 도달할 때까지 기다릴 필요 없이 컴파일 시점에서 오류를 해결할 수 있습니다.

여기서 Generics의 두 번째 이점을 알 수 있습니다. 이제 Iterator는 typesafe 특성을 갖게 되었습니다. Iterator 인터페이스의 next() 메소드는 컬렉션 중 다음 요소의 typesafe 버전을 반환합니다.

그러나 이번 팁에서는 2005 Core Java Technologies Tip에서 다룬 바 있는 Generics의 사용법에 대해 소개하지 않습니다. Generics를 사용할 때 extends 키워드의 용도를 제대로 모르는 사람들이 많습니다. 형태를 그리는 예제를 통해 extends의 사용법을 설명하는 것이 일반적입니다. 그 대신에 이번 테크팁에서는 추가로 새 클래스를 만들 필요 없이 Swing 구성요소를 사용하는 예제를 활용하겠습니다. 매우 한정된 경우지만, 다음은 Object가 실제 루트인 Swing 버튼 구성요소의 클래스 계층 구조입니다.

Component
|- Container
   |- JComponent
      |- AbstractButton
         |- JButton
         |- JMenuItem
            |- JCheckBoxMenuItem
            |- JMenu
            |- JRadioButtonMenuItem
         |- JToggleButton
            |- JCheckBox
            |- JRadioButton

모든 AbstractButton 하위 클래스가 공유하는 것 중 하나가 getText() 메소드입니다. 따라서 Generics의 원칙에 따라, AbstractButton 항목의 List를 가져오는 메소드를 정의하고 이 버튼의 String 레이블 List를 반환할 수 있습니다. 다음은 그러한 메소드의 첫 번째 버전입니다.

  public static List<String> getLabels(List7lt;AbstractButton> list) {
    List<String> labelList = new ArrayList<String>(list.size());
    for (AbstractButton button: list) {
      labelList.add(button.getText());
    }
    return labelList;
  }

그리고 이 메소드를 사용할 수 있는 방법을 소개합니다. 먼저 AbstractButton 유형의 List를 정의하고 이를 채운 다음 메소드를 호출합니다.

  List<AbstractButton> buttonList =
      new ArrayList<AbstractButton>();
  buttonList.add(new JButton("Hello"));
  buttonList.add(new JCheckBox("World"));
  buttonList.add(new JRadioButton("Hola"));
  buttonList.add(new JMenuItem("Mundo"));

  List labels = getLabels(buttonList);
  System.out.println(labels);

"Hola, Mundo"는 Google에 따르면 "Hello, World,"를 스페인어로 번역한 것입니다. println() 호출의 결과는 다음과 같습니다.

[Hello, World, Hola, Mundo]

AbstractButtonsList를 사용하면 모두 제대로 작동하지만, List가 다른 것일 때, 특히 하위 클래스인 경우 문제가 발생합니다. JButtonAbstractButton의 하위 클래스이므로 JButton 항목의 List를 사용해도 무방할 것이라 생각하기 쉽습니다. AbstractButtonListgetLabels(List<AbstractButton>)을 호출할 수 없을까요?

  List<JButton> buttonList = ...
  // ... Fill list ...
  List<String> labels = getLabels(buttonList);

그렇지 않군요. 이는 컴파일 시점의 검사이고 getLabels()의 정의에서 오로지 AbstractButton List만 받아들이도록 규정되었으므로, 다른 어떤 것도 전달할 수 없습니다. 컴파일 시점의 오류 메시지는 다음과 같습니다.

GetList.java:13: getLabels(java.util.List<javax.swing.AbstractButton>)
  in GetList cannot be applied to (java.util.List<javax.swing.JButton>)

    List<String> labels = getLabels(buttonList);
                          ^
1 error

그리고 여기서 extends 키워드가 진가를 발휘합니다. getLabels() 메소드가 AbstractButton 목록만 허용하도록 정의하지 않고 AbstractButton 하위 클래스의 모든 List를 허용하도록 정의합니다.

    public static List<String> getLabels(
      List<? extends AbstractButton> list) {

여기서 와일드카드 ?는 AbstractButton의 하위 클래스라면 메소드에서는 정확한 클래스 유형이 무엇이든 개의치 않음을 나타냅니다. 모든 조각을 짜맞춘 전체 예제를 소개하자면 다음과 같습니다.

import java.util.*;
import javax.swing.*;

public class GetList {
  public static void main(String args[]) {
    List<JButton> buttonList =
      new ArrayList<JButton>();
    buttonList.add(new JButton("Hello"));
    buttonList.add(new JButton("World"));
    buttonList.add(new JButton("Hola"));
    buttonList.add(new JButton("Mundo"));

    List labels = getLabels(buttonList);
    System.out.println(labels);

  }

  public static List<String> getLabels(
        List<? extends AbstractButton> list) {
    List<String> labelList = new ArrayList<String>(list.size());
    for (AbstractButton button: list) {
      labelList.add(button.getText());
    }
    return labelList;
  }
}

이제는 Generics를 사용하여 직접 클래스와 메소드를 정의하면서 추상 클래스를 generic 인수 또는 모든 하위 클래스로 받아들이려는 경우, 와일드카드를 사용하여 동일한 메소드가 하위 클래스에서도 최상의 기능을 발휘하게 하십시오.

Generics에 대한 자세한 내용은 Gilad Bracha가 작성했던 두 튜토리얼, 2004 Tutorial(PDF)과 온라인 Java Tutorial의 Generics 단원을 참조하십시오


이 글의 영문 원본은
Using Generics With Wildcards and Extends
에서 보실 수 있습니다.

"Java SE" 카테고리의 다른 글

2008/04/07 18:15 2008/04/07 18:15

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/541

댓글을 달아 주세요

[로그인][오픈아이디란?]

◀ Prev 1  ... 110 111 112 113 114 115 116 117 118  ... 624  Next ▶