다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입을 체크해 주는 기능
객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌.
제네릭스의 장점
타입의 안정성을 제공함.
타입체크의 형변환을 생략할 수 있으므로 코드가 간결해짐.
1.2. 제네릭 클래스의 선언
// 여기서 T는 임의의 참조형 타입이다.
// T에 원하는 타입을 지정하여 사용할 수 있다.
class Box<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"); // OK
String item = (String)b.getItem(); // 형변환이 필요없음
주의사항
제네릭 타입을 지정하지 않아도 객체 생성이 허용되지만 안전하지 않다는 경고가 발생
타입 변수 T에 Object타입을 지정하면, 경고가 발생하지 않음
제네릭스 용어
Box<T> : 제네릭 클래스, ‘T의 Box’ 또는 ‘T Box’라고 읽는다.
T : 타입 변수 또는 타입 매개변수. (T는 타입 문자)
Box : 원시 타입(raw type)
제네릭스 제한
T는 인스턴스변수로 간주되기 때문에 모든 객체에 대해 동일하게 동작해야 하는 static멤버에 타입 변수 T를 사용할 수 없음
제네릭 타입의 배열 선언은 가능하나 배열을 생성하는 것은 허용되지 않음
new 연산자는 컴파일 시점에 타입을 정확하게 알고 있어야 함.
1.3. 제네릭 클래스의 객체 생성과 사용
참조변수와 생성자에 대입된 타입이 일치해야 함.
두 타입이 상속관계에 있는 경우에도 대입된 타입은 일치해야 함.
JDK1.7부터는 추정이 가능한 경우 타입을 생략할 수 있게 됨.
Box<Apple> appleBox = new Box<>(); // JDK1.7부터 가능
Box<Apple> appleBox = new Box<Apple>(); // OK
Box<Apple> appleBox = new Box<Grape>(); // 에러
Box<Fruit> appleBox = new Box<Apple>(); // 에러
1.4. 제한된 제네릭 클래스
타입 매개변수 T에 지정할 수 있는 타입의 종류를 제한하는 방법이 존재함.
제네릭에 extends 를 사용하면 특정 타입의 자손들만 대입할 수 있게 제한할 수 있음.
인터페이스를 구현하는 제약을 사용할 때에도 extends 를 사용한다.
class FruitBox<T extends Fruit> { // Fruit의 자손 타입만 지정가능
ArrayList<T> list = new ArrayList<T>();
...
}
1.5. 와일드 카드
// 매개변수에 과일박스를 대입하면 주스를 만들어 반환하는 클래스
class Juicer {
static Juice makeJuice(FruitBox<Fruit> box) {
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
}
이 경우, 제네릭 타입을 FruitBox<Fruit> 로 고정해버리면 Apple 과 같은 다른 과일의 타입을 활용할 수 없는 문제가 발생
이럴 때 사용하기 위해 고안된 것이 와일드 카드이며 와일드 카드 기호는 “?” 로 표현
extends 와 super 로 제한할 수 있음.
<? extends T> : 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> : 제한 없음. 모든 타입이 가능
1.6. 제네릭 메서드
메서드의 선언부에 제네릭 타입이 선언된 메서드를 제네릭 메서드라 한다.
제네릭 메서드는 제네릭 클래스가 아닌 클래스에서도 정의가 가능하다.
// Collections.sort()
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){
...
}
}
2. 열거형(Enum)
2.1. 열거형(Enum)이란?
서로 관련된 상수를 편리하게 선언하기 위한 기능
자바의 열거형은 값뿐만 아니라 타입도 관리하기 때문에 논리적 오류를 줄일 수 있음
class Card {
enum Kind { CLOVER, HEART, DIAMOND, SPADE }
enum Value { TWO, THREE, FOUR }
final Kind kind;
final Value value;
}
2.2. 열거형의 정의와 사용
enum 열거형이름 { 상수명1, 상수명2, ... }
enum Direction { EAST, SOUTH, WEST, NORTH }
class Unit {
int x, y;
Direction dir;
void init() {
dir = Driection.EAST;
}
}
열거형 상수간의 비교는 == 를 사용할 수 있음.
열거형의 메서드
메서드
설명
Class<E> getDeclaringClass()
열거형의 Class객체를 반환
String name()
열거형 상수의 이름을 문자열로 반환
int ordinal()
열거형 상수가 정의된 순서를 반환 (0부터 시작)
T valueOf(Class<T> enumType, String name)
지정된 열거형에서 name과 일치하는 열거형 상수를 반환
static E values()
열거형에 정의된 모든 상수를 출력
열거형의 값 지정하기
enum Direction {
EAST(1), SOUTH(5), WEST(-1), NORTH(10);
private final int value;
Direction(int value) { this.value = value; }
public int getValue() { return value; }
}
3. 애너테이션(Annotation)
3.1. 애너테이션(Annotation)이란?
소스코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각하고 개발을 했다고 한다..
소스코드의 주석 /** ~ */ 에 소스코드에 대한 정보를 저장하고, 소스코드 주석으로부터 HTML문서를 생성하는 프로그램(javadoc.exe)을 만들어 사용함.
이 기능을 응용해서 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 애너테이션이다.
애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 줄 수 있음