ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CH05 제네릭, ITEM 26 로타입은 사용하지 말라
    카테고리 없음 2022. 10. 2. 08:49

     

    제네릭 타입 (Generic Type)

    제네릭 타입은 타입을 파라미터로 가지는 클래스 또는 인터페이스를 말한다. 

    public class 클래스명<T> { ... }
    public interface 인터페이스명 <T> { ... }

     

    컴파일 시 강한 타입 체크를 할 수 있다. 

    자바 컴파일러는 잘못 사용된 타입으로 인해 발생하는 문제점을 제거하기 위해 제네릭 코드에 강한 타입 체크를 한다. 

    런타임시 타입 에러보다는 컴파일 시점에 미리 타입을 체크하여 에러를 사전에 방지하는 것이 좋다. 

     

    타입 변환(castring)을 제거한다. 

    비제네릭 코드는 불필요한 타입 변환으로 프로그램 성능에 악영향을 미친다. 


    로 타입 (Row Type)

    로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않은 경우를 말한다. 

    ex) List<E> → 로타입 List 

    로타입은 타입 선언에서 제네틱 타입 정보가 전부 지워진 것처럼 동작한다.

    왜 로타입을 사용하는가?

    " 제네릭 도래하기 전 코드와 호환성 "

    로타입을 사용하게 되면, 제네릭이 안겨주는 안전성과 표현성을 모두 잃게 된다. 

     

     

    제네릭 선언 시 컴파일러는 stemps 변수에는 Stemp 인스턴스만 넣어야 컴파일러가 인지한다.

    stemps 변수에 다른 타입의 인스턴스를 넣는 경우 컴파일 에러가 발생하여 잘못된 부분을 알려준다.  

    // Stemp 인스턴스만 취급하는 변수 선언 
    private final Collection stemps = ...;			// 제네릭 지원 전 : 로타입 선언 
    private final Collection<Stemp> stemps = ...;		// 제네릭 지원 후
    
    // 로타입 선언 시 런타임 시 "unchecked call" 경고 발생 
    // 제네릭 선언 시 컴파일 에러 발생 
    stemps.add(new Coin(...));

     

    Question 1 | 로타입 List와 매개변수 타입 List<Object>의 차이는 무엇일까? 

    List : 제네릭 타입에서 완전히 발을 뺀 것 

    List<Object> : 모든 타입을 허용한다는 의사를 컴파일러에게 밝힌 것 

    public static void main (String[] args) {
    	List<String> strings = new ArrayList<>();
        unsafeAdd(strings, Integer.valueOf(42));
        safeAdd(strings, Integer.valueOf(42));
        
        // 컴파일러가 자동으로 형변환 코드를 넣어준다.
       	String s = strings.get(0);				 // 1) ClassCastException에러 발생 
    }
    
    // 1) 로타입 파라미터 메서드
    private static void unsafeAdd (List list, Object o) {
    	list.add(o);
    }
    
    // 2) 매개변수화 타입 파라미터 메서드 
    private static void safeAdd (List list<String>, Object o) {
    	list.add(o);							// 2) 컴파일 에러 발생 
    }

     

     

    제네릭 타입을 쓰고 싶지만 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않다면 비한정 와일드카드 타입을 사용하자. 

    static int numElementsInCommon(Set s1, Set s2) {
    	int result = 0;
        for(Object o1 : s1) 
        	if(s2.contains(o1)) 
            	result++;
        return result;
    }

     

    Question 2 | 로타입 Set과 비한정적 와일드 타입 Set<?>의 차이는 무엇일까?

    " 안정성 "

    로 타입 컬렉션에서는 아무 원소나 넣을 수 있으니 타입 불변식을 훼손하기 쉽다. 

    반면 Collection<?> 에는 (null 외에는) 어떤 원소도 넣을 수 없다. 

     

     

    * 로타입을 사용해야 하는 경우 

    1) class 리터럴에는 로 타입을 써야 한다.

    Class Literals : 클래스, 인터페이스, 배열 타입들의 이름 또는 기본 타입, void 뒤에 "." 이 따라오고 class 토큰이 붙는
    형식으로 구성된 표현법

    자바 명세에서 class 리터럴에 매개변수화 타입을 사용하지 못하게 했기 때문이다. 

    ex) List.class, String[].class, int.class ---> O

          List<String>.class, List<?>.class  ---> X

     

     

    2) instanceof 연산자는 비한정적 와일드카드 타입 이외에 매개변수화 타입에는 적용할 수 없다. 

    로타입이든 비한정적 와일드카드 타입이든 완전히 똑같이 동작한다. 깔끔하게 로타입을 쓰는 것이 깔끔하다. 

    instanceof 연산자 : 객체가 어떤 클래스인지 어떤 클래스를 상속 받았는 지 확인하는 데 사용 (boolean)
    if (o instanceof Set) {			// 로타입
    	Set<?> s = (Set<?>) o;
        ...
    }

    Study 

    Question | 비한정적 와일드 타입과 매개변수 타입에서 Object 를 사용할 경우의 차이는 있나요 ? 

     

    댓글

Designed by Tistory.