[자바의 정석] 지네릭스, 열거형, 애너테이션
열거형 enums
서로 관련된 상수를 편리하게 선언하기 위한 것으로 C언어의 열거형보다 더 향상되어 열거형이 갖는 값뿐만 아니라 타입도 관리
class Card{
enum Kind {Clover, Heart, Diamond, Spade} //0,1,2,3
enum Value {Two, Three, Four} //0,1,2
final Kind kind; //상수이기 때문에 final
final Value value;
}
자바의 열거형은 타입이 다르더라도 값이 값이 같으면 True를 리턴하는 것과 달리 값과 타입이 모두 같아야 에러가 발생하지 않는다.
if(Card.Clover == Card.Two) // Card 타입(타입 갖고), Clover(0) == Two(0) → True
if (Card.Kind.Clover == Card.Value.Two) // Kind와 Value타입이 다르므로 → False
열거형의 중요한 점 하나로 원래는 상수의 값이 바뀌면, 해당 상수를 참조하는 모든 소스를 다시 컴파일 해야하지만 열거형 상수를 사용하면 기존의 소스를 다시 컴파일 할 필요가 없다.
열거형 정의
// 열거형 정의
enum Direction {EAST, WEST, SOUTH, NORTH}
class Unit{
int x, y;
Direction dir; // 열거형을 인스턴스로 생성
void init(){
dir = Direction.EAST;
if (dir == Direction.EAST){ //열거형은 ==으로 비교가능
x++;
}
else if (dir > Direction.WEST){ //열거형은 비교연산 사용 불가
}
else if (dir.compareTo(Direction.WEST) > 0){ // compateTo로 비교
}
}
}
열거형 멤버 추가
Enum Class에 정의된 ordinal()이 열거형 상수가 정의된 순서를 반환(0부터 1,2,3)하지만, 이 값을 열거형 상수의 값으로 사용하지 않는 것이 좋다.
불연손적일 경우에는 다음과 같이 사용한다.
enum Direction {EAST(1), SOUTH(5), WEST(-1), NORTH(10)}
enum Direction {
//반드시 ';' 붙여야 한다.
EAST(1, ">"), SOUTH(2,"V"), WEST(3, "<"), NORTH(4,"^");
// 먼저 열거형 상수를 정의를 한 뒤에 멤버를 추가해야 한다.
private static final Direction[] DIR_ARR = Direction.values();
private final int value;
private final String symbol;
Direction(int value, String symbol) { // private Direction(int value)
this.value = value;
this.symbol = symbol;
}
public int getValue() { return value; }
public String getSymbol() { return symbol; }
public static Direction of(int dir) {
if (dir < 1 || dir > 4) {
throw new IllegalArgumentException("Invalid value :" + dir);
}
return DIR_ARR[dir - 1];
}
// 방향을 회전시키는 메서드. num의 값만큼 90도씩 시계방향으로 회전한다.
public Direction rotate(int num) {
num = num % 4;
if(num < 0) num +=4; // num이 음수일 때는 시계반대 방향으로 회전
return DIR_ARR[(value-1+num) % 4];
}
public String toString() {
return name()+getSymbol();
}
} // enum Direction
위에 코드는 단순히 enum에 멤버 변수를 어떻게 추가하고, 추가하기 위한 제약사항을 설명하기 위한 코드이다.
열거형에 추상메서드
// 열거형으로 운송수단을 선언했다.
// 각 운송수단마다 요금이 다르기 때문에 요금을 계산하는 추상메서드를 선언해야한다.
enum Transportation {
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;}};
protected final int BASIC_FARE; // protected로 해야 각 상수에서 접근가능
//생성자
Transportation(int basicFare) { // private Transportation(int basicFare) {
BASIC_FARE = basicFare;
}
public int getBasicFare() { return BASIC_FARE; }
// 추상메서드 선언
abstract int fare(int distance); // 거리에 따른 요금 계산
}
열거형에 추상메서드를 선언하는 일은 많지 않으므로 참고만!
애너테이션 (annotation)
소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
주석처럼 프로그래밍 언어에 영향을 미치지 않으면 유용한 정보를 제공
표준 애너테이션
-
@Override
: 메서드 앞에만 붙을 수 있는 애너테이션으로, 조상의 메서드를 오버라이딩 하는 것오버라이팅 할 때 메서드의 이름을 잘못 작성할 경우가 있는데, 컴파일러는 오타로 인식하는 것이 아닌 새로운 매서드가 추가된 것으로 인식한다. 하지만 @Override를 사용하면, 컴파일러가 같은 이름의 메서드가 있는지 확인하고 없으면 에러 발생
-
@Deprecated
: 다른 것으로 대체된 필드나 매서드에 붙여 이제 사용되지 않는 다는 것을 알린다. -
@FunctionalInterface
: 함수형 인터페이스를 선언할 때, 컴파일러가 인터페이스를 올바르게 선언했는지 확인할 때 사용
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
//FunctionalInterface 애너테이션이 있으므로 인터페이스의 추상메서드가 1개보다 많을 경우 애러 발생
- @SuppressWarnings
: 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제. 경고가 발생한 것을 알면서도 묵인할 때 사용
억제 범위는 최소한으로 해야 추가된 코드에서 발생한 경고를 확인할 수 있다.
@SuppressWarnings({"deprecation", "unchecked"})
ArrayList list = new ArrayList(); //지네릭 타입을 지정하지 않아 경고가 발생하나 묵인
list.add(obj);
- @SafeVarargs
: 메서드에 선언된 가변인자의 타입이 non-reifiable타입일 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 unchecked 경고가 발생하는데, 해당 코드에 문제가 없다면 경고를 출력하지 않기 위해 사용
메타 애너테이션
애너테이션에 붙이는 애너테이션으로 애너테이션을 정의할 때 애너테이션의 적용대상이나 유지기간을 지정
@Target
애너테이션이 적용가능한 대상을 지정하는데 사용
@Target({TYPE, FILED, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
TYPE: 타입을 선언할 때 / TYPE_USE: 타입의 변수를 선언할 때
@Target ({FIELD, TYPE, TYPE_USE})
public @interface MyAnnotation(){}
@MyAnnotation()
class MyClass{ //Type
@MyAnnotation()
int i; // FIELD : 필드는 기본형
@MyAnnotation()
MyClass mc; //TYPE_USE : 타입 변수 선언
}
@Retention
애너테이션이 유지되는 기간을 지정
-
SOURCE
: @Override 또는 @SuppressWarnings 같이 컴파일러가 사용하는 애너테이션에는 Source -
RUNTIME
: 실행시에 리플렉션을 통해 클래스 파일에 저장된 애니터이션의 정보를 읽어서 처리 -
CLASS
: 컴파일러가 애너테이션의 정보를 클래스 파일에 저장할 수 있게는 하지만, JVM이 로딩될 때는 애너테이션의 정보가 무시되어 실행시에 애너테이션 정보를 얻을 수 없다.
→ 그래서 잘 안씀
@Inherited
애너테이션이 자손 클래스에 상속되도록 하며, 만약 조상클래스에 Inherited를 붙이면 자손클래스에도 애너테이션이 적용된 것과 같다.
@Repeatable
하나의 대상에 여러 애너테이션을 적용할 때 사용
@Repeatable(ToDos.class)
@interface ToDo{
String value();
}
@ToDo("Delete")
@ToDo("Override")
class MyClass{}
애너테이션 타입 정의
@interface 애너테이션이름{
타입요소이름(); //애너테이션 요소
}
애너테이션을 정의하는 방법은 인터페이스를 정의하는 것과 같고 앞에 @만 붙이면 된다.
@interface DateTime{
String yymmdd();
String hhmmss();
}
모든 애너테이션의 조상은 Annotation인데 이는 상속을 허용하지 않으므로 extends Annotation으로 명시할 수 없다.
애너테이션 요소 규칙
요소의 타입은 기본형, String, enum, 애너테이션, class만 가능
()안에 매개변수를 선언 불가
예외 선언 불가
요소를 타입 매개변수로 정의 불가
@interface AnnoTest{
int id = 100; //상수 선언 가능 ⭕️
String major(int i, int j); // 매개변수 선언 불가 ❌
String minor() throws Excpetion; //예외불가 ❌
ArrayList<T> list(); //요소 타입에 타입 매개변수 불가 ❌
}
Author And Source
이 문제에 관하여([자바의 정석] 지네릭스, 열거형, 애너테이션), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@orpsh1941/자바의-정석-지네릭스-열거형-애너테이션저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)