다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크(compile-time type check)를 해주는 기능
- 타입 안정성 제공
- 코드가 간결해짐(타입체크/형변환 생략 가능)
클래스명<T>
T : 임의의 참조형 타입 의미
ex)
class Box<T> { // 지네릭 타입 T를 선언
T item;
void setItem(T item) {
this.item = item;
}
T getltem() {
return item;
}
}
Box<Apple>.item
과 Box<Grape>.item
이 다른 것이어서는 안 됨T[] arr;
instanceof
☑️ 참조변수 타입 = 생성자에 대입된 타입
상속관계에 있는 클래스 간에도 호환 불가능
Box<Apple> appleBox = new Box<Apple> () ; // OK
Box<Apple> appleBox = new Box<Grape> () ; // 에러(Apple-Grape 두 클래스가 상속관계에 있더라도)
☑️ (JDK1.7~) 추정이 가능한 경우 타입 생략 가능
Box<Apple> appleBox = new Box<Apple>();
Box<Apple> appleBox = new Box<> (); // OK. JDK1.7부터 생략가능
☑️ 메서드의 매개변수로는 상속관계에 있는 클래스의 객체 사용 가능
//Fruit : 부모 클래스, Apple : Fruit의 자식 클래스
Box<Fruit> fruitBox = new Box<Fruit> () ;
fruitBox.add (new Fruit ()); // OK.
fruitBox.add (new Apple ()); // OK. void add (Fruit item)
classFruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정가능
ArrayList<T> list = new ArrayList<T>() ;
...
}
class FruitBox<T extends Eatable> { ... }
class FruitBox<T extends Fruit & Eatable> { ... }
기호 | 의미 |
---|---|
<? extends T> | 와일드 카드의 상한 제한. T와 그 자손들만 가능 |
<? super T> | 와일드 카드의 하한 제한. T와 그 조상들만 가능 |
<?> | 제한 없음. 모든 타입이 가능. <? extends Object> 와 동일 |
메서드의 선언부에 지네릭 타입이 선언된 메서드
(지네릭 클래스가 아닌 클래스에도 정의될 수 있음, static메서드에도 사용 가능)
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.printIn (Juicer.<Apple>makeJuice (appleBox));
ex)
generic <-> non-generic 간의 형변환 : 항상 가능, 경고 발생
BoX box = null;
Box<Object> objBox = null;
box = (Box) objBox; // OK. 지네릭 타입 -> 원시 타입. 경고 발생
objBox = (Box<Object>) box; // OK. 원시 타입 -> 지네릭 타입. 경고 발생
대입된 타입이 다른 지네릭 타입 간의 형변환
Box<Object> objBox = null;
Box<String> strBox = null;
objBox = (Box<Object>) strBox; // 에러. Box<String> -> Box<Object>
strBox = (Box<String>) objBox; // 에러. Box<Object> -> Box<String>
대팁된 타입이 서로 상속관계에 있는 경우
Box<? extends Object〉 wBox = new Box<String>(); // OK
FruitBox<? extends Fruit> box = new FruitBox<Fruit> () ; // OK
FruitBox<? extends Fruit> box = new FruitBox<Apple> () ; // OK
FruitBox<? extends Fruit> box = new FruitBox<Grape> () ; / / OK
Optional<?> wopt = new Optional<Object>();
Optional<Object> oopt = new Optional<Object>() ;
Optional<string> sopt = (Optional<String>)wopt; // OK. 형변환 가능
Optional<String> sopt = (Optional<String>)oopt; // 에러. 형변환 불가
FruitBox<? extends Object> objBox = null;
FruitBox<? extends String> strBox = null;
strBox = (FruitBox<? extends string>)objBox; // OK. 미확정 타입으로 형변환 경고
ObjBox = (FruitBox<? extends Object>)strBox; // OK. 미확정 타입으로 형변환 경고
☑️ 컴파일러의 작업 순서 : 지네릭 타입을 이용해서 소스파일 체크 -> 필요한 곳에 형변환 삽입 -> 지네릭 타입 제거
☑️ 지네릭 타입 제거 이유 : 지네릭 도입 이전의 소스 코드와 호환성을 유지하기 위해서
☑️ 지네릭 타입 제거 과정
1. 지네릭 타입의 경계(bound)를 제거 : <T extends Fruit>
-> T를 Fruit으로 대체
2. 지네릭 타입을 제거한 후에 타입이 일치하지 않으면 형변환을 추가
서로 관련된 상수를 편리하게 선언하기 위한 것
여러 상수를 정의할 때 사용하면 유용
class Card {
enum Rind { CLOVER, HEART, DIAMOND, SPADE } // 열거형 Kind를 정의
enum Value { TWO, THREE, FOUR } //열거형 Value를 정의
final Kind kind;// 타입이 int가 아닌 Kind임에 유의
final Value value;
☑️ 타입에 안전한 열거형(typesafe enum) : 값이 같아도 타입이 다르면 컴파일 에러 발생
if (Card.CLOVER == Card.TWO) // OK
if (Card.Kind.CLOVER == Card.Value.TWO) // 컴파일 에러. 값은 같지만 타입이 다름
enum 열거형이름{ 상수명1, 상수명2, ...}
모든 열거형의 조상 - java.lang.Enum
각 열거형 상수는 각각의 객체
ex)
enum Direction { EAST, SOUTH, WEST, NORTH }
=
class Direction ‹
static final Direction EAST = new Direction ("EAST");
static final Direction SOUTH = new Direction ("SOUTH");
static final Direction WEST = new Direction ("WEST"');
static final Direction NORTH = new Direction ("NORTH");
private String name;
private Direction (String name) {
this.name = name;
}
}
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
== 주석(프로그래밍 언어에 영향x)
애너테이션을 위한 애너테이션(=dㅐ너테이션에 붙이는 애너테이션)
애너테이션을 정의할 때 애너테이션의 적용대상(target)이나 유지기간(retention)등을 지정하는데 사용
@Target
: 애너테이션에 적용할 수 있는 대상@Retention
: 애너테이션이 유지(retention)되는 기간을 지정(소스파일, 클래스 파일, 실행시 등)@Documented
: 애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다@lnherited
: 애너테이션이 자손 클래스에 상속되도록 한다@Repeatable
: 보통은 하나의 대상에 한 종류의 애너테이션을 붙이는데,‘@Repeatable’이 붙은 애너테이션은 여러 번 붙일 수 있다.@Native
: 네이티브 메서드(native method)에 의해 참조되는 ‘상수 필드(constant field)’에 붙이는 애너테이션@interface 애너테이션이름 {
타입 요소이름(); //애너테이션의 요소를 선언
...
}
*애너테이션에도 인터페이스처럼 상수를 정의할 수 있지만.디폴트 메서드는 정의할 수 없다.
애너테이션 내에 선언된 메서드
@interface AnnoTest {
int id = 100; // OK. 상수선언. static final int id = 100;
String major(int i, int j); // 에러. 매개변수를 선언할 수없음
String minor() throws Exception; // 에러. 예외를 선언할 수 없음
ArrayList<T> list(); // 에러. 요소의 타입에 타입 매개변수 사용불가
}
요소가 하나도 정의되지 않은 애너테이션(Serializable이나 Cloneable 인터페이스)