Java - 2. Generics - 기본

갓김치·2020년 9월 17일
0

고급자바

목록 보기
8/47

Generic?

  • 클래스에 사용할 타입을 디자인(설계)시에 지정하는 것이 아니라 클래스를 사용할 때 지정한 후 사용하는 기술

장점

  • 컴파일 시 잘못된 타입 사용을 체크하기 때문에 타입 안전 (Type Safety) 코딩을 할 수 있다.
  • 불필요한 타입변환(casting)을 하지 않아도 된다. (프로그램 성능 향상)

제너릭 클래스 만드는 방법

              ┌─▶ 컴파일해서 사용하는 시점에는 타입문자가 뭔지 알려줘야한다.
class 클래스명<제너릭타입글자> {
  제너릭타입글자 변수명; // 변수선언에 제너릭을 사용할 경우
  ...

  제너릭타입글자 메서드명() { // 반환값이 있는 메서드에서 사용
    ...

    return;
  }
  ...
}

제너릭타입글자

  • T: Type
  • K: Key
  • V: Value
  • E: Element (자료구조에 들어가는 항목들을 나타낼 때 사용)

예시

1단계: NonGeneric 클래스와 MyGeneric 클래스 생성

class NonGeneric {
  private Object val;

  public Object getVal() {
      return val;
  }
  public void setVal(Object val) {
      this.val = val;
  }

} // NonGenric

class MyGeneric<T> {
  private T val;

  public T getVal() { 
      return val;
  }
  public void setVal(T val) {
      this.val = val;
  }

} // MyGeneric

2단계: NonGeneric, MyGeneric비교

public class T02_Generic {
  public static void main(String[] args) {
    NonGeneric ng1 = new NonGeneric();
    ng1.setVal("가나다라");

    NonGeneric ng2 = new NonGeneric();
    ng2.setVal(100);
    
    // NonGeneric: 각 타입에 맞도록 형변환을 해줘야함
    String rtnNg1 = (String)ng1.getVal();
    Integer irtnNg2 = (Integer)ng2.getVal();
    // 문자열 반환값 rtnNg1 => 가나다라
    // 정수형 반환값 irtnNg2 => 100
    
    // Generic
    // 사용하는 시점에 반드시 타입을 지정해줘야 함
    // 사용하는 시점에 '한 종류'로 제한을 둠
    MyGeneric<String> mg1 = new MyGeneric<String>();
    MyGeneric<Integer> mg2 = new MyGeneric<>();

    mg1.setVal("우리나라");
    mg2.setVal(500);

    rtnNg1 = mg1.getVal();
    irtnNg2 = mg2.getVal();
    // 제너릭 문자열 반환값 rtnNg1 => 우리나라
    // 제너릭 정수형 반환값 irtnNg2 => 500
  }
}

참고

  • T02_Generic.java

제너릭 메서드 만드는 법

제너릭 메서드 <T, R> R method(T t)
  • 파라미터 타입과 리턴타입으로 타입 파라미터를 가지는 메서드
  • 선언방법: 리턴타입 앞에 <> 기호를 추가하고 타입 파라미터를 기술 후 사용함.

예시

1. 멀티타입<K, V>를 가지는 제너릭 클래스

class Pair<K, V> {
  private K key;
  private V value;

  public Pair(K key, V value) { // 생성자
      super();
      this.key = key;
      this.value = value;
  }

  public K getKey() {
      return key;
  }

  public void setKey(K key) {
      this.key = key;
  }

  public V getValue() {
      return value;
  }

  public void setValue(V value) {
      this.value = value;
  }

  // 키와 값 출력하는 메서드
  // 클래스의 <K, V>와 메서드의 <K, V>는 별개 ★★
  // 메서드의 K, V는 메서드 안에서만 유효
  public <K, V> void displayAll(K key, V value) {
      System.out.println(key.toString() + " : " + value);
  }
}

2. 제너릭 메서드를 갖는 Util 클래스

class Util{
  public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {

    boolean keyCompare = p1.getKey().equals(p2.getKey());
    boolean valueCompare = p2.getValue().equals(p2.getValue));

    return keyCompare && valueCompare;
  }
}

3. 제너릭 메서드 활용

public class T03_GenericMethodTest {

  public static void main(String[] args) {

    Pair<Integer, String> p1 = new Pair<Integer, String>(1, "홍길동");
    Pair<Integer, String> p2 = new Pair<Integer, String>(1, "홍길동");

                            //┌─▶ 구체적 타입을 명시적으로 지정 (생략가능)
    boolean result1 = Util.<Integer, String>compare(p1, p2); // true
    // 결과: p1과 p2는 논리적(의미)으로 동일한 객체임.


    Pair<String, String> p3 = new Pair<String, String>("001", "홍길동");
    Pair<String, String> p4 = new Pair<String, String>("002", "홍길동");

    boolean result2= Util.compare(p3, p4); // false
    // 결과: p3과 p4는 논리적(의미)으로 동일한 객체 아님.

    // 제너릭 메서드 호출
    p1.<String, Integer>displayAll("키값", 1234); // 꺽쇠 생략 가능
    // 출력: 키값 : 1234


  } // main
	
} // T03_GenericMethodTest

참고

  • T03_GenericMethodTest.java
profile
갈 길이 멀다

0개의 댓글