JAVA의 정석 | Chapter 12 지네릭스

Yunny.Log ·2022년 7월 5일
0

JAVA

목록 보기
21/29
post-thumbnail
post-custom-banner

12.1 Generics

  • 컴파일 시 타입을 체크해주는 기능
  • 객체 타입 안정성 상승, 형변환 번거로움은 reduced
  • 제네릭스가 없을 당시의 단점
ArrayList list = new ArrayList();
list.add(10)
list.add("20")

Integer i = (Integer)list.get(1); 
//"20" 을 integer로 형변환하는것
  • 위와 같이 코드 작성해도 컴파일러에선 에러 못 잡고 RUN 된다.
  • 런할 때서야 비로소 ClassCastException 발생
  • 왜냐면 컴파일 시 실제로 안에 뭐가 있는지는 알 수 없기 때문이죠
  • 실행 시 에러보다 컴파일 에러가 훨씬 좋은 것!

  • 참조변수, 생성자에 T대신 실제 타입을 지정하면 형변환 생략 가능 => 어떤 타입이 들어올 지 이미 알기 때문이지

12.2 타입 변수

  • 클래스 작성 시 Object 타입 대신 타입 변수(E)를 선언해서 사용

  • 기본적으로 타입 변수는 대문자 하나로 쓰는 것이 일반적임

    12.3 타입 변수에 대입하기

  • 객체 생성 시 타입 변수(E) 대신 실제 타입(Tv) 지정, 대입

  • 타입 변수 E 대신 실제 타입 Tv를 넣어줘야 함

  • 타입 변수 대신 실제 타입 지정 시, 형변환 생략 가능

    12.4 용어

    용어 : 지네릭 클래스 / 타입 변수 / 원시 타입

  • 다형성도 성립한다, 따라서 타입 매개변수의 자손들도 들어가기 가능 ㅇ

여러 개의 타입 변수가 필요하면, 콤마를 구분자로 선언

class TwoGen<T, V> { 
      T ob1;
      V ob2;
      
        TwoGen( T o1, V o2 ) {
        ob1 = o1;
        ob2 = o2;
  }
    void showTypes() {
        System.out.println("Type of T : " + ob1.getClass().getName());
        System.out.println("Type of V : " + ob2.getClass().getName());
        }
        T getob1() { return ob1; } 
        V getob2() { return ob2; }
    }
  
  public class Test2 {
      public static void main(String[] args) {
      TwoGen<Integer, String> x = new TwoGen<Integer, String>(55, "Hello");
      x.showTypes();
      int v = x.getob1();
      System.out.println("value : " + v);
      String w = x.getob2();
      System.out.println("value : " + w);
  }
}

Bounded Types : 제한된 제네릭 클래스

  • Type parameter를 제한할 필요 시

  • Generics는 어떤 타입의 객체든 사용할 수 있도록 하겠다는 의미가 있음

  • 그러나 특정 클래스들은 제한된 타입의 매개변수만 처리하기를 원함

example : 아래 코드 에러


  class NumericFns<T> {
      T num;
      NumericFns(T n) {
      num = n;
  	}
    
  double reciprocal() {
      return 1/num.doubleValue(); // num의 역수를 구하고자 함.
  	}
    
  double fraction() {
    return num.doubleValue() - num.intValue(); // num의 소수 부분만 구하고자 함.
  	}

}
  • doubleValue 이런 것은 Number class 타입들에게만 가능, 그러나 Generic은 모든 타입을 허용해서 에러,

    에러인 이유 : Generics는 어떤 타입의 객체든 사용할 수 있도록 하겠다는 의미가 있는데 Number 클래스의 하위 클래스들에만 사용할 수 있는 메소드를 사용

  • 따라서 위와 같은 경우 방지 위해 Type parameter를 명시할 때, 인수로 넣을 수 있는 클래스를 제한 필요

<T extends S> T에는 클래스 S의 객체 또는 S의 하위 클래스 객체만 오도록 하기 가능

지네릭스 제한

  • static 멤버에는 타입 변수 T 사용 불가!

  • static은 모든 인스턴스에 적용되기 때문이지

  • 지네릭 타입의 배열 T[ ] 생성 허용 x

와일드 카드 ‘?’

  • 지네릭 타입에 와일드 카드를 쓰면, 여러 타입을 대입가능
  • 단, 와일드 카드에는 <? extends T & E>와 같이‘&’를 사용불가

  • Bounded Wildcards : 특정 부모 클래스의 자식 클래스 객체에 대해 메소드를 작
    성할 때 유용

와일드 카드 사용의 이유

  class Foo<T extends Number> {

    T num;

    Foo ( T n ) { num = n; }

   boolean same( Foo<T> ob ) {
// *** same 메소드를 호출하는 객체와 패러미터 ob에 전달
// 되는 객체는 같은 타입이어야 한다.

          if (Math.abs(num.doubleValue()) == Math.abs(ob.num.doubleValue())) 
          return true;
          return false;
        }
    }

    public class Test5 {
      public static void main(String[] args) {

        Foo<Float> x = new Foo<Float>(2.5f);
        Foo<Double> y = new Foo<Double>(-2.5);

		// 따라서 x의 same 메소드 매개변수는 무조건 Float여야 하는데, 
		// float이 들어갔다구 에러를 튕기게 되는 것 
        if ( x.same(y) ) System.out.println("same"); // 에러 발생
        else System.out.println("different");
      }
  }
  • 따라서 하나의 매개변수로 확정짓는 것이 아니라, 여러 종류의 타입을 허용해주는 것이 필요함 => 그것이 바로 wild card

  • 와일드 카드로 위 코드를 수정해내보자 (아래코드로)

class Foo<T extends Number> {
  T num;
  Foo ( T n ) { num = n; }

  boolean same( Foo<?> ob ) {
  	// same에 들어가는 매개변수를 와일드카드로 정의
    
    if (Math.abs(num.doubleValue()) == Math.abs(ob.num.doubleValue())) 
    return true;
    return false;
	  }
  }
  
  public class Test6 {
    public static void main(String[] args) {
    
      Foo<Integer> i = new Foo<Integer>(6);
      Foo<Double> d = new Foo<Double>(-6.0);
      Foo<Long> l = new Foo<Long>(5L);
  
  	// 그럼 SAME의 매개변수로 일치하는 타입이 오지 않아도 OK
      if ( i.same(d) ) System.out.println("i, d -> equal");
      else System.out.println("i, d -> different");
      if ( i.same(l) ) System.out.println("i, l -> equal");
      else System.out.println("i, l -> different");
  }
}

Generic method

◆ Generic 메소드는 parameter에 generics를 적용한다.
◆ Generic 메소드에서는 type parameter가 return type 앞에 와야 한다.
◆ Generic 클래스가 아니어도 generic 메소드 가질 수 있다.
◆ Generic 메소드는 static / nonstatic 모두 가능

post-custom-banner

0개의 댓글