Continuous Challenge

[Java의 정석_연습문제 풀이] Chapter12 Generics, Enumeration, Annotation(지네릭스, 열거형, 애너테이션) 본문

Study/Java의 정석

[Java의 정석_연습문제 풀이] Chapter12 Generics, Enumeration, Annotation(지네릭스, 열거형, 애너테이션)

응굥 2019. 11. 5. 15:13
728x90
728x90

[12-1] 클래스 Box가 다음과 같이 정의되어 있을 때, 다음 중 오류가 발생하는 문장은? 경고가 발생하는 문장은?

class Box<T> { //지네릭 타입 T를 선언   

T item; 

void setItem(T item) { this.item = item; } 

T getItem() { return item; } }

}

a. Box<Object> b = new Box<String>( ); //에러. 대입된 타입이 반드시 같아야 한다.

b. Box<Object> b = (Object)new Box<String>( ); //에러. Object타입을 Box<Object>타입의 참조변수에 저장불가. (타입 불일치)

c. new Box<String>( ).setItem(new Object( )); //에러. 대입된 타입이 String이므로, setItem(T item)의 매개변수 역시, String타입만 허용된다.

d. new Box<String>( ).setItem("ABC"); //OK. 대입된 타입인 String과 일치하는 타입을 매개변수로 지정했기 때문에 OK.


답 : a, b, c



[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;

}

}

a. Juicer.<Apple>makeJuice(new FruitBox<Fruit>( ));

//에러. 지네릭 메서드에 대입된 타입이 Apple이므로, 이 메서드의 매개변수는 'FruitBox<Apple>'타입이 된다. new FruitBox<Fruit>( )는 매개변수의 타입과 일치하지 않으며, 자동형변환도 불가능한 타입이므로 에러이다.

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

//에러. Grape가 Fruit의 자손이라고 해도, 타입이 다르기 때문에 같은 이유로 에러.

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

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

//OK. 지네릭 메서드의 타입 호출이 생략된 형태. 생략하지 않았다면, 'Juicer.<Apple>makeJuice(new FruitBox<Apple>( ));'과 같다. 대부분의 경우 이처럼 생략한다.

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

//에러. 지네릭 메서드의 타입 호출이 생략되지 않았다면, 'Juicer.<Object>makeJuice(new FruitBox<Object>( ));' 과 같다. d번의 경우와 같이 타입이 일치하긴 하지만, <T extends Fruit>로 제한이 걸려있으므로, 타입 T는 Fruit의 자손이어야 한다. Object는 Fruit의 자손이 아니므로 에러.


답 : a, d c, d


[12-3] 다음 중 올바르지 않은 문장을 모두 고르시오.

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

T item;


void setItem(T item) {this.item = item;}

T getItem() {return item;}

}

a. Box<?> b = new Box( );

//OK. Box<?>는 Box<? extends Object>를 줄여쓴 것이다. 객체 생성에 지네릭 타입을 지정해 주지 않았지만 문제가 되지는 않는다. 그래도, new Box<>( ) 대신 new Box( )를 사용하는 것이 좋다.

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

//OK. new Box<>( );는 타입을 생략한 것으로, 일반적으로는 참조변수의 타입과 같은 타입으로 간주된다. 참조변수의 타입이 <?>, 즉 <? extends Object>이므로 생략된 타입은 Object이라고 생각하기 쉬운데, 여기서는 지네릭 클래스 Box에 정의된 타입이 T extends Fruit>와 같이 제한되어 있기 때문에, 'Obect'가 아니라 'Fruit'이 생략된 것으로 봐야 한다. 그래서 Box<?> b = new Box<Object>( );와 같이 하면 에러가 발생한다. Object는 Fruit의 자손이 아니기 때문이다.

Box<?> b = new Box<>( ); //OK. Box<?> b = new Box<Fruit>( ); 와 동일

Box<?> b = new Box<Object>( ); //에러

Box<?> b = new Box<Fruit>( ); //OK.

'Box<? extends Object>'는 Box<Object>와 같지 않음에 주의하자. 지네릭 클래스 Box는 타입 T가 Fruit의 자손으로 제한되어 있기 때문에, Box<Object>와 같이 Fruit의 자손이 아닌 클래스를 대입할 수 없다. 그러나, 'Box<? extends Object>'와 같이 와일드 카드를 사용하는 것은 가능하다.

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

d. Box<Object> b = new Box<Fruit>( ); //에러. 타입 불일치

e. Box              b = new Box<Fruit>( ); //OK. 바람직하지 않음. 'Box<?> b'가 더 나음.

f. Box<? extends Fruit> b = new Box<Apple>( ); //OK.

g. Box<? extends Object> b = new Box<? extends Fruit>( ); //에러. new연산자는 타입이 명확해야하므로 와일드카드와 같이 사용불가.


답 : c, d, g


[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-5] 아래는 예제 7-3에 열거형 Kind와 Number를 새로 정의하여 적용한 것이다. (1)에 알맞은 코드를 넣어 예제를 완성하시오. (Math.random( )을 사용했으므로 실행결과가 달라질 수 있다.)

class DeckTest {

public static void main(String args[]) {

Deck d = new Deck(); // 카드 한 벌(Deck)을 만든다.

Card c = d.pick(0); // 섞기 전에 제일 위의 카드를 뽑는다.

System.out.println(c); // System.out.println(c.toString());과 같다.


d.shuffle(); // 카드를 섞는다.

c = d.pick(0); // 섞은 후에 제일 위의 카드를 뽑는다 .

System.out.println(c);

}

}


class Deck {

final int CARD_NUM = Card.Kind.values().length * Card.Number.values().length;// 카드의 개수

Card cardArr[] = new Card[CARD_NUM]; // Card객체 배열을 포함


Deck() {

/*

* (1) 알맞은 코드를 넣어서 완성하시오. 

* Deck의 카드를 초기화한다 .

*/

}


Card pick(int index){ 지정된 위치 에 있는 카드 하나를


꺼내서 반환

(index) return cardArr[index]; }


Card pick() { // Deck에서 카드 하나를 선택한다.

int index = (int) (Math.random() * CARD_NUM);

return pick(index);

}


void shuffle() { // 카드의 순서를 섞는다.

for (int i = 0; i < cardArr.length; i++) {

int r = (int) (Math.random() * CARD_NUM);

}


Card temp = cardArr[i];

cardArr[i] = cardArr[r];

cardArr[r] = temp;

}

}


//Card 클래스 

class Card {

enum Kind {CLOVER, HEART, DIAMOND, SPADE}

enum Number {ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING}


Kind kind;

Number num;


Card() {

this(Kind.SPADE, Number.ACE);

}


Card(Kind kind, Number num) {

this.kind = kind;

this.num = num;

}


public String toString() {

return "[" + kind.name() + "," + num.name() + "]";

}

}


[실행결과]

[CLOVER,ACE]

[HEART,TEN]

답 :

(1)

int i = 0;


for(Card.Kind kind : Card.Kind.values()){

for(Card.Number num : Card.Number.values()) {
    cardArr[i++] = new Card(kind,num);

}

}


[12-6] 다음 중 메타 에너테이션이 아닌 것을 모두 고르시오.

a. Documented

b. Target

c. Native

d. Inherited

답 : c


 애너테이션

설명 

 @Override

 컴파일러에게 오버라이딩하는 메서드라는 것을 알린다. 

 @Deprecated

 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.

 @SuppressWarnings 

 컴파일러의 특정 경고메시지가 나타나지 않게 해준다. 

 @SafeVarargs 

 지네릭스 타입의 가변인자에 사용한다. (JDK1.7) 

 @FunctionalInterface 

 함수형 인터페이스라는 것을 알린다. (JDK1.8) 

 @Native 

 native메서드에서 참조되는 상수 앞에 붙인다. (JDK1.8)

 @Target * 

 애너테이션이 적용가능한 대상을 지정하는데 사용한다. 

 @Documented * 

 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.  

 @Inherited * 

 애너테이션이 자손 클래스에  

 @Retention * 

 애너테이션이 유지되는 범위를 지정하는 데 사용한다. 

 @Repeatable * 

 애너테이션을 반복해서 적용할 수 있게 한다. (JDK1.8) 

[자바에서 기본적으로 제공하는 표준 애너테이션 (*가 붙은 것은 메타 애너테이션)]



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

@interface TestInfo { 

int count() default 1; 

String[] value() default "aaa"; 

}

a. @TestInfo                     class Exercise12_7 { }

//default값이 지정되어 있는 요소는 애너테이션을 적용할 때값을 생략할 수 있다.

b. @TestInfo(1)                 class Exercise12_7 { }

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

  '@TestInfo(count=1)'이라고 써야 맞음.

c. @TestInfo("bbb")            class Exercise12_7 { }

//@TestInfo(count =1, value = {"bbb"})의 생략된 형태

d. @TestInfo("bbb", "ccc")    class Exercise12_7 { } 

//요소의 타입이 배열이고, 지정하려는 값이 여러 개인 경우 괄호{ }가 필요함.

@TestInfo({"bbb","ccc"}) 또는 @TestInfo(value={"bbb","ccc"})와 같이 써야함.

답 : b, d


728x90
728x90
Comments