2 minute read

예제 12-1

클래스 Box가 다음과 같이 정의되어 있을 때 다음 중 오류가 발생하는 문장은?

경고가 발생하는 문장은?

class Box<T> { // 지네릭 타입 T를 선언
    T item;
    
    void setItem(T item) {
    this.item = item;
    }
    
    T getItem() {
    return item;
    }
}

  1. Box<Object> b = new Box<String>();

대입된 타입이 다르므로 에러

  1. Box<Object> b = (Object)new Box<String>();

(Object)Box<String>과 Box<Object>는 타입이 다르다.

정확히 뭐가 다른지는 모르겠으나 그렇게 이해하기로 했다. ..

  1. new Box()<String>.setItem(new Object());

대입된 타입이 String만 가능하므로, SetItem의 매개변수 역시 String만 가능하다.

  1. new Box()<String>.setItem(“ABC”);

“ABC”는 String타입이므로 OK

예제 12-2

지네릭 메서드 makeJuice() 가 아래와 같이 정의되어 있을 때 이 메서드를 올바르게 호출한 문장을 모두 고르시오 Apple과 Grape는 Fruit의 자손이라고 가정하자.

class Juicer {
    static <T extends Fruit> String makeJuice(FruitBox<T> box) {
        String tmp = "";
        
        for(Fruit f : box.getList())
       		 tmp += f + " ";
        return tmp;
    }
}
  1. Juicer.<Apple>makeJuice(new FruitBox<Fruit>());

    제너릭 메서드의 타입이 Apple이면

    메서드의 매개변수는 FruitBox<Apple>이어야 한다.

  2. Juicer.<Fruit>makeJuice(new FruitBox<Grape>());

    자손관계에 있는 경우에도 타입이 다르면 안된다.

  3. Juicer.<Fruit>makeJuice(new FruitBox<Fruit>());

    OK

  4. Juicer.makeJuice(new FruitBox<Apple>());

    OK. 메서드의 타입 호출이 생략된 형태

  5. Juicer.makeJuice(new FruitBox<Object>());

    생략되지 않은 형태는

    Juicer.<Object>makeJuice(new FruitBox<Object>());

    T extends Fruit의 조건에 부합하지 않아 에러

예제 12-3

다음 중 올바르지 않은 문장을 모두 고르시오.

class Box<T extends Fruit> { // T 지네릭 타입 를 선언
    T item;

    void setItem(T item) {
    	this.item = item;
    }
    
    T getItem() {
  	 	 return item;
    }
}
  1. Box<?> b = new Box();

    Box<?> = Box<? extends Object>.

    new Box()대신 new Box<>()를 사용해 주는게 좋긴 하지만 OK

  2. Box b = new Box<>();

    Box<>()는 타입을 생략한 것으로, 일반적으로 참조변수의 타입과 같은 타입으로 간주된다.

    생략된 타입은 Object가 아니라 지네릭 클래스 Box의 타입인 T extends Fruit이 생략된 것이다. 그래서 new Box<Object>라고 하면 에러난다.

  3. Box<?> b = new Box<Object>();

    위의 이유로 에러

  4. Box<Object> b = new Box<Fruit>();

    자손관계라도 타입 불일치이면 에러

  5. Box b = new Box<Fruit>();

    OK. Box<?> b로 표기하는 게 낫다고 함.

  6. Box<? extends Fruit> b = new Box<Apple>();

    굿굿

  7. Box<? extends Object> b = new Box<? extends Fruit>();

    new 연산자는 타입이 명확해야 한다.

    와일드 카드처럼 애매하게 사용 불가

예제 12-4

아래의 메서드는 두 개의 ArrayList를 매개변수로 받아서 하나의 새로운 ArrayList로 병합하는 메서드이다. 이를 지네릭 메서드로 변경하시오.

public static ArrayList<? extends Product> merge(
    ArrayList<? extends Product> list, 
    ArrayList<? extends Product> list2) {
    ArrayList<? extends Product> newList = new ArrayList<>(list);
    
    newList.addAll(list2);
    
    return newList;
}

public static <T extends Product> ArrayList<T> merge(
    ArrayList<T> list, ArrayList<T> list2) {
    ArrayList<T> newList = new ArrayList<>(list);
    newList.addAll(list2);
    return newList;
}

지네릭 메서드에 선언된 지네릭 타입은

지역 변수를 선언한 것과 같다고 보면 된다고 한다.

예제 12-6

애너테이션 TestInfo가 다음과 같이 정의되어 있을 때, 이 애너테이션이 올바르게 적용되지 않은 것은?

@interface TestInfo {
    int count() default 1;
    String[] value() default "aaa";
}
  1. @TestInfo class Exercise12_7 {}

    default값이 지정되어 있을 때는 값을 생략해도 된다.

  2. @TestInfo(1) class Exercise12_7 {}

    요소의 이름이 value가 아닌 경우에는 값을 생략할 수 없다.

    @TestInfo(count=1) 가 정답.

  3. @TestInfo(“bbb”) class Exercise12_7 {}

  4. @TestInfo(“bbb”,”ccc”) class Exercise12_7 {}

    요소의 타입이 배열이고, 지정하려는 값이 여러 개인 경우 괄호를 써주어야 한다.

    @TestInfo({“bbb”, “ccc”}) @TestInfo(value={“bbb”,”ccc”})가 정답.

Updated: