
지네릭스의 장점
- 타입 안정성을 제공한다.
- 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.
class Box<T>{ // 지네릭 타입 T를 선언
T item;
void setItem(T item) { this.item = item; }
T getItem() { return item; }
}
Box<String> b = new Box<String>(); // 타입 T대신, 실제 타입을 지정
b.setItem(new Object); // 에러. 실제 String이외의 타입은 지정불가
b.setItem("ABC")
String item = b.getItem(); // 형변환이 필요없음
class Box< T > {}
- Box< T > : 지네릭 클래스. 'T의 Box' 또는 'T Box'라고 읽는다.
- T : 타입 변수 또는 타입 매개변수.(T는 타입문자)
- Box : 원시 타입(raw type)
Box<String> b = new Box<String> ();
Box<Apple> appleBox = new Box<Apple>();
Box<Grape> grapeBox = new Box<Grape>();
class Box<T>{
ArrayList<T> list = new ArrayList<T> ();
void add(T item) {list.add(item);}
T get(int i) {return list.get(i);}
ArrayList<T> getList() {return list;}
int size() {return list.size();}
public String toString() {return list.toString();}
}
Box<Apple> appleBox = new Box<Apple>(); // ok
Box<Fruit> appleBox = new Box<apple>(); // 상속관계도 안됨 XXXX
Box<Apple> appleBox = new Box<>(); // ok. 생략가능
appleBox.add(new Apple()); // ok
appleBox.add(new Grape()); // Apple객체만 추가가능 XXXX
class FruitBox<T extends Fruit>{ // Fruit의 자손만 타입으로 지정가능
ArrayList<T> list = new ArrayList<T>();
...
}
interface Eatable {}
class FtuitBox<T extends Eatable> { ... }
class FruitBox<T extends Fruit & Eatable>
- < ? extends T > : 와일드 카드의 상한 제한. T와 그 자손들만 가능
- < ? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
- < ? > : 제한 없음. 모든 타입이 가능<? extends Object>와 동일
- Comparator<? super Apple> : Comparator< Apple >, Comparator< Fruit >, Comparator< Object >
- Comparator<? super Grape> : Comparator< Grape >, Comparator< Fruit >, Comparator< Object >
static <T> void sort(List<T> list, Comparator<? super T> c)
지네릭 메서드는 지네릭 클래스가 아닌 클래스에도 정의할 수 있다.
class FruitBox<T>{
...
static<T> void sort(List<T> list, Comparator<? super T> c){
....
}
}
// 변경 전
static Juice makeJuice(FruitBox<? extends Fruit> box){
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
// 변경 후
static <T extends Fruit> Juice makeJuice(FruitBox<T> box){
String tmp = "";
for (Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
// 호출시
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
....
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.<Apple>makeJuice(appleBox));
class Card{
enum Kind {CLOVER, HEART, DIAMOND, SPADE} // 열거형 Kind를 정의
enum Value {TWO, THREE, FOUR} // 열거형 Value를 정의
final Kind kind; // 타입이 int가 아닌 Kind임
final Value value;
}
열거형을 정의하는 방법은 다음과 같이 괄호{}안에 상수의 이름을 나열하기만 하면 된다.
enum 열거형 이름 {상수명1, 상수명2, ...}
열거형 상수간의 비교에는 '=='를 사용할 수 있다. 또한 비교연산자는 사용할 수 없고 compareTo()는 사용가능하다.
// enum Direction {EAST(1), SOUTH(5), WEST(-1), NORTH(10)}
enum Direction {
EAST(1), SOUTH(5), WEST(-1), NORTH(10);
private final int value; // 정수를 저장할 필드를 추가
Direction(int value) {this.value = value;} // 생성자 추가, 제어가자 묵시적으로 private
public int getValue() {return value;}
}
enum Direction {
EAST(1,">"), SOUTH(5, "V"), WEST(-1, "<"), NORTH(10, "^");
private final int value;
private final String symbol;
Direction(int value, String symbol) {
this.value = value;
this.symbol = symbol;
}
public int getValue() {return value;}
public String getSymbol() {return symbol;}
}
#### 열거형에 추상 메서드 추가하기
```java
enum Transfortation{
BUS(100) {
int fare(int distance) { return distance*BASIC_FARE; }
},
TRAIN(150) {
int fare(int distance) { return distance*BASIC_FARE; }
},
SHIP(100) {
int fare(int distance) { return distance*BASIC_FARE; }
},
AIRPLANE(300) {
int fare(int distance) { return distance*BASIC_FARE; }
};
abstract int fare (int distance);
protected final int BASIC_FARE;
Transportation(int basicFaer){
BASIC_FARE = basicFare;
}
piblic int getBasicFare(); {return BASIC_FARE;}
}
애너테이션(annotation)의 뜻은 주석, 주해, 메모이다.
// 둘이상을 사용할 경우
@SuppressWarnings({"deprecation", "unchecked", "varargs"})
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings{
String[] value();
}
@interface 애너테이션이름 {
타입 요소이름(); // 애너테이션의 요소를 선언한다.
...
}
애너테이션에도 인터페이스처럼 상수를 정의할 수 있지만, 디폴트 메서드는 정의할 수 없다.
@interface TestInfo(){
int count();
String testedBy();
String[] testTools();
TestType testType(); // enum Test{FIRST, FINAL}
DateTime testDate(); // 자신이 아닌 애너테이션(@Datetime)을 포함할 수 있다.
}
@interface DateTime(){
String yymmdd();
String hhmmss();
}
@TestInfo(
count = 3, testedBy="Kim",
testTools = {"JUnit", "AutoTester"},
testType = TestType.FIRST,
testDate = @DateTime(yymmdd="160101", hhmmss="235959")
)
public class NewClass { ... }
- 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용된다.
- ()안에 매개변수를 선언할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 저으이할 수 없다.