지네릭스
다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스 컴파일 시의 타입체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.
선언
1
2
3
4
5
6
7
8
9
10
class Box<T>{
T item;
void setItem(T item) {this.item = item;}
T getItem() {return item}
}
Box<String> b = new Box<String>();
b.setItem(new Object()); // String 타입이 아니기 때문에 에러
b.setItem("ABC");
String item = b.getItem();
** 타입변수는 꼭 T를 사용하지 않아도 되며 타입변수가 여러개인 경우 Map<K, V>와 같이 콤마를 구분자로 나열하면 된다.
- static 멤버에 타입 변수 T를 사용할 수 없다. ex) Box< Apple >.item 과 Box< Grape >.item이 달라선 안된다.
- 지네릭타입의 배열을 생성할 수 없다.
- 지네릭 클래스끼리 상속됐을 경우 사용할 수 있지만 대입된 타입이 상속관계에 있다고 다르게 사용할 수는 없다. ex) Box< Fruit > appleBox = new Box < Apple >(); (X) Box< Apple > appleBox = new FruitBox < Apple >(); (O)
- class FruitBox< T extends Fruit > 과 같이 선언하게 되면 타입에 Fruit의 자손 타입만 담을 수 있게 된다.
1
2
3
4
5
6
class Juicer {
static Juice makeJuice(FruitBox<Fruit> box){
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
** 위와 같이 static에 지네릭스를 적용할 수 없다.
1
2
3
4
5
6
class Juicer {
static Juice makeJuice(FruitBox<? extends Fruit> box){
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
** ? extends T = 자손들만 가능 ? super T = 조상들만 가능 ? = 모든 타입 가능
열거형
서로 관련된 상수를 편리하게 선언하기 위한 것으로 여러 상수를 정의할 때 사용하면 유용하다.
1
2
3
4
5
6
7
class Card{
enum Kind { CLOVER, HEART, DIAMOND, SPADE }
enum Value { TWO, THREE, FOUR }
final Kind kind;
final Value value;
}
** 열거형 상수의 값이 불연속적인 경우 CLOVER(2), HEART(4) 이런식으로 ()를 이용해주면 된다. - 현재 CLOVER(1), TWO(1)과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum Direction {
EAST(1, ">"), SOUTH(2,"V"), WEST(3, "<"), NORTH(4,"^");
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; }
}
** 하나의 열거형 상수에 여러 값을 지정할 수 있다. 하지만 그에 맞게 인스턴스 변수와 생성자 등을 추가해주어야 한다. 외부에서 접근할 수 있도록 메서드도 추가해주었다.
1
2
3
4
5
6
7
public Dirction rotate(int num){
num = num % 4;
if(num < 0) num += 4;
return DIR_ARR[(value-1+num) % 4]; // DIR_ARR[] = Direction.values()
} // Direction enum 내의 함수.
System.out.println(Direction.EAST.rotate(1)); // 이런식으로 사용 가능하며 결과는 SOUTH
** enum 에서의 추상클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
enum Transportation{
BUS(100) {int fare(int distance) {return distance * BASIC_FARE; } }
TRAIN(150) {int fare(int distance) {return distance * BASIC_FARE; } }
protected final int BASIC_FARE;
Transportation(int basicFare) { BASIC_FARE = basicFare; } // Bus(100)에서 100이 BASIC_FARE가 된다.
abstract int fare(int distance);
}
System.out.println(Transportation.BUS.fare(120)); // 100 * 120이 fare가 된다.
System.out.println(Transportation.TRAIN.fare(120)); // 150 * 120
애너테이션(annotation)
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것. 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점이 있다.
- 표준 애너테이션
애너테이션 | 설명 |
---|---|
@Override | 컴파일러에게 오버라이딩하는 메서드라는 것을 알림 |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 붙임 |
@SuppressWarnings | 컴파일러의 특정 경고메시지가 나타나지 않게 해줌 |
이 외에 여러 애너테이션들이 있다.
** @Override 를 붙일 경우 오버라이딩 시 함수명 실수 등을 잡아 줄 수 있다.
- 애너테이션 타입 정의
1
2
3
4
5
6
7
8
9
10
@interface Testinfo{
int count();
String testsedBy();
String[] testTools();
}
@TestInfo(
count = 3, testedBy = "Kim",
testTools = { "JUnit", "AutoTester" }
)