반응형
Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
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 31
Archives
Today
Total
관리 메뉴

지식조각모음

12. 제네릭스, 열거형, 애너테이션 본문

책/자바의 정석

12. 제네릭스, 열거형, 애너테이션

y00 2022. 3. 13. 15:52
반응형

Generics

의미

  • 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미
  • 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
  • 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능

간단히 말해서, 어떤 타입을 사용할지 미리 지정하는 것이다.

왜 사용할까?

제네릭을 통해 컴파일 시 타입 체크를 미리 수행하면 다음과 같은 장점이 있다.

  1. 객체의 타입 안정성을 높인다.
    • 컴파일 타임에 객체의 타입을 체크한다. 이때 에러가 발생하면 runtime 에러보다 안전하게 에러를 체크할 수 있다.
  2. 형변환의 번거로움이 줄어든다.
  3. 반환값에 대한 현변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.
    • 예를 들어 반환값이 Object로 되어 있으면 intger로 변환할 때 많은 부분을 고려해야 한다. 하지만 특정 타입으로 지정되어 있으면 이런 번거로움을 줄일 수 있다.
  4. 코드의 재사용성을 높일 수 있다.
    • 타입만 변경하면 동일한 코드를 매번 작성할 필요없다.

예 - generic type을 사용하지 않는 경우

public class Box {
    private Object object;

    public void set(Object object) { this.object = object; }
    public Object get() { return object; }
}

위와 같은 Box 클래스가 있다고 해보자. 이 클래스는 어떤 타입이든 받아서 사용할 수 잇으며 컴파일 시점에는 이 클래스가 어떻게 사용될 지 알 수 없다. 실제로 사용할 때 어떤 타입을 지정할 지, 어떤 타입을 받게 될지 모른다. get메소드를 호출하는 경우 Integer 타입을 받아야 하지만 실수로 String타입을 받도록 코드를 짤 수도 있다. 이런 경우 runtime 에러가 발생하게 된다.

Box box = new Box();
box.set(1);

// Pass
int boxResult = box.get();

// runtime error 발생
String boxResult = box.get(); 

또는 매번 타입 검사를 해야한다. 예를 들어 ArrayList를 생성할 때 타입을 지정하지 않는다면 아래 예제처럼 매번 형변환(cast)를 해야한다.

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

generic type

용어

class Box<T> {}
  • Box<T>: 제네릭 클래스. 'T Box'라고 읽는다
  • Box: 원시 타입(raw type)
  • T: 타입 변수 또는 타입 매개변수

타입 변수에 타입을 지정하는 것을 '제네릭 타입 호출'이라고 하고, 타입 변수 대신 지정된 타입을 '대입된 타입(parameterized type)'이라고 한다.

타입변수

클래스 이름 옆의 '<>'안에 있는 E를 '타입 변수(type variable)'라고 하며, 일반적으로는 'Type'의 첫 글자를 따서 T를 사용한다. generic 클래스는 다음과 같은 포맷을 따른다. 참고로 <>은 영어로 angle brackets이다.

class name<T1, T2, ..., Tn> { /* ... */ }

이런 타입변수는 아래와 같은 naming 컨벤션을 따른다. (참고)

  • E - Element (used extensively by the Java Collections Framework)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

또한 타입 변수를 여러개로 지정할 수 있다.

public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
    this.key = key;
    this.value = value;
    }

    public K getKey()    { return key; }
    public V getValue() { return value; }
}


// example
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<String, String>("hello", "world");

심지어는 타입 변수에 타입 변수를 사용할 수도 있다. 예를 들어 Pair 클래스를 선언할 때 타입 변수에 Box<Integer>을 사용하여 다음과 같이 사용할 수 있다.

OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));

예 - generic type을 사용하는 경우

public class Box<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

public interface List <E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}

generic 제한

타입 문자로 사용할 타입을 명시하면 한 종류의 타입만 저장할 수 있다. 하지만 여전히 모든 종류의 타입을 지정할 수 있다.

FruitBox<Toy> fruitBox = new FruitBox<Toy>(); // 과일 상자에 장난감을 담을 수 있다.

특정 타입만 사용할 수 있도록 하려면 extends를 사용해야 한다. 이러면 특정 타입의 자손들만 대입할 수 있게 제한할 수 있다.

class FruitBox<T extends Fruit> { ... }    // Fruit의 자손만 타입으로 지정 가능

FruitBox<Toy> fruitBox = new FruitBox<Toy>(); // 에러 발생

Enum

  • 상수들의 집합

  • 예: 일반적인 상수 선언 방식

    Class Card {
      static final int CLOVER = 0;
      static final int HEART = 1;
      static final int DIAMOND = 2;
      static final int SPADE = 3;
    
      static final int TWO = 0;
      static final int THREE = 1;
      static final int FOUR = 2;
    
      final int kind;
      final int num;
    }

    위와 같이 선언한 것을 열거형을 이용하여 변경할 수 있다.

    class Card {
      enum Kind {CLOVER, HEART, DIAMOND, SPADE}
      enum Value {TWO, THREE, FOUR}
    
      final Kind kind;
      final Value value;
    }
반응형

' > 자바의 정석' 카테고리의 다른 글

14. 람다와 스트림  (2) 2022.04.09
13. 스레드  (2) 2022.03.30
Comparator와 Comparable  (1) 2022.03.10
11. 컬렉션 프레임웍  (0) 2022.03.06
10. 날짜와 시간 & 형식화  (1) 2022.03.05