Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

forDevLife

[자바의정석] Chap 12. 열거형, 애너테이션 본문

Java

[자바의정석] Chap 12. 열거형, 애너테이션

JH_Lucid 2021. 3. 10. 01:43

2.1 열거형이란?

- 서로 관련된 상수를 편리하게 선언하기 위한 것으로, 여러 상수를 정의할 때 사용하면 유용

- 타입에 안전한 열거형(typesafe enum)으로, 실제 값이 같아도 타입이 다르면 컴파일 에러 발생

 

2.4 열거형의 이해

- 열거형 상수 하나하나는 Direction 객체이다.

- 모든 열거형은 추상클래스 Enum의 자손이다. 

- 추상클래스는 객체를 생성할 수 없다. 추상클래스의 자손은 자동으로 만들어진다?

   > 객체를 생성할 수 없고, 미리 추상클래스의 정의에서 만드는 것으로 보인다.

- 열거형 예제(p700)에 대해서 많은 고민 결과, 그냥 받아들인다.

   > 추상메서드 없이도 추상 class로 정의 가능하다.

   > 열거형에 추상메서드를 추가하면, 각 열거형 상수의 정의에 메서드를 정의해야 한다. 

    + 난 바보다. 익명클래스를 다시 공부 해야한다....

    > 익명클래스로 추상클래스를 상속받으므로 내부에서 추상메서드를 구현해야 한다. 또한 추상클래스 내의 변수를 사용하기 위해선 이게

       protected / public으로 선언되어 있어야 한다..!

 

3.2 표준 애너테이션

@Override

- 메서드 앞에만 붙일 수 있는 애너테이션으로, 조상의 메서드를 오버라이딩 하는 것을 컴파일러에게 알려주는 역할을 한다.

 

@Deprecated

- 대상이 다른 것으로 대체되었으니, 더 이상 사용하지 않을 것을 권한다는 의미이다.

- 컴파일 옵션으로 -Xlint:deprecation(-Xlint만 쓰면 다른 것도 다같이 나오는 듯) 을 작성하면 컴파일 시 자세한 내용을 알 수 있다.

 

@FunctionalInterface

- 함수형 인터페이스를 선언할 때 (뒤에서 배움), 이를 붙이면 컴파일러가 '함수형 인터페이스'를 올바르게 선언했는지 확인한다. 실수 방지용

 

@SuppressWarnings

- 컴파일러가 보여주는 경고메세지가 나타나지 않게 억제해준다. 

- SuppressWarnings("~")를 통해 억제할 수 있는 경고메세지를 지정해준다.

   -. deprecation : @Deprecated 붙은 대상 경고를 억제

   -. unchecked : 지네릭스로 타입을 지정하지 않았을 때 발생하는 경고 억제

   -. rawtypes : 지네릭스를 사용하지 않아서 발생하는 경고 억제

   -. varargs : 가변인자의 타입이 지네릭 타입일 때 발생하는 경고를 억제

   -> 아래 3개는 지네릭스 관련된거라 좀 헷갈린다. 

- 둘 이상의 경고 동시 억제 시 @SuppressWarnings({"deprecation", "unchecked"}) 중괄호 사용한다.

 

@SafeVarargs

- 메서드에 선언된 가변인자의 타입이 non-reifiable타입일 경우 해당 메서드 선언부와 호출부에서 unchecked 경고 발생. 

- 이를 억제하기 위해 사용

- static, final 붙은 메서드와 생성자에만 붙일 수 있다. (오버라이드 될 수 있는 메서드에는 사용 불가)

* reifiable : 다시 ~화 하다. 컴파일 후에도 타입 정보가 유지되는 경우이다. 

                  컴파일 후에도 제거되지 않는 타입(유지)을 reifiable이라고 하고, 제거되는 타입을 non-reifiable이라고 한다. 

                  앞에서 배운 것 처럼, generic은 타입이 컴파일시에 제거되므로 non-reifiable하다.

- 메서드를 선언할 때 @SafeVarargs를 붙이면, 이 메서드를 호출하는 곳에서 발생하는 경고도 억제된다.

- 반면에 @SafeVarargs 대신, @SuppressWarnings("unchecked")로 경고를 억제하려면 메서드 선언 및 호출 둘 다 애너테이션을 붙여야 한다. 

- 따라서, @SafeVarargs와 @SuppressWarnings("unchecked")는 동일한 역할을 한다. 다만 varargs경고도 함께 억제해줘야 하기 때문에 @SuppressWarnings("varargs")가 대부분 함께 작성된다.(가능하면 함께 작성)

 

3.3 메타 애너테이션

메타 애너테이션은 '애너테이션을 위한 애너테이션', 즉 애너테이션을 정의할 때 애너테이션의 적용대상, 유지기간을 지정하는데 사용된다.

 

@Target

- 애너테이션 적용 가능한 대상을 지정하는데 사용된다.

- FIELD는 기본형에, TYPE_USE는 참조형에 사용된다.

- 아래처럼 ElementType을 import하면, @Target에서 적용 대상을 지정할 때 그 이름만 작성한다. 원래 ElementType.FIELD 등으로 작성

import static java.lang.annotation.ElementType.*;

@Target({FIELD, TYPE, TYPE_USE}) //적용 대상이 FIELD, TYPE, TYPE_USE
public @interface MyAnnotation { } // MyAnnotation을 정의

@MyAnnotation //적용 대상이 Type(class, interface, enum)
class MyClass {
	@MyAnnotation // 적용 대상이 FIELD(멤버변수, enum 상수)
	int i;
	
	@MyAnnotation // 적용 대상이 TYPE_USE(타입이 사용되는 모든 곳)
	MyClass mc;
}

 

@Retention

- 애너테이션이 유지되는 기간을 지정하는데 사용된다. 

 

   -. SOURCE : 소스파일에만 존재, 클래스 파일에는 존재하지 않음.

      > @Override 처럼 컴파일러가 사용하는 애너테이션은 유지정책이 SOURCE이다. 컴파일러 직접 작성할 것 아니면 필요없다.

 

   -. CLASS : 클래스 파일에 존재, 실행시에 사용불가. 기본값

     > 컴파일러가 애너테이션의 정보를 클래스 파일에 저장할 수 있게는 하지만, 클래스 파일이 JVM에 로딩될 때는

        애너테이션의 정보가 무시되어 실행시에 애너테이션에 대한 정보를 얻을 수 없다. 유지정책의 기본값임에도 잘 사용되지 않는다. 

 

   -. RUNTIME : 클래스 파일에 존재, 실행시에 사용가능

     > 실행 시에 리플렉션을 통해 클래스 파일에 저장된 애너테이션의 정보를 읽어서 처리할 수 있다. 

     > 지역 변수에 붙은 애너테이션은 컴파일러만 인식할 수 있으므로, 유지정책이 RUNTIME일 경우에도 실행 시 인식되지 않는다.

 

@Documented

- 애너테이션에 대한 정보고 javadoc으로 작성된 문서에 포함되도록 한다. 자바에서 제공하는 기본 애너테이션 중에 @Override와 

@SuppressWarnings를 제외하고는 모두 이게 붙어 있다.

 

@Inherited

- 애너테이션이 자손 클래스에 상속되도록 한다. 

@Inherited
@interface SupperAnno {}

@SupperAnno
class Parent { }

class Child extends Parent {} // Child에도 애너테이션 붙은 것으로 인식 

 

@Repeatable

- 보통은 하나의 대상에 한 종류의 애너테이션을 붙이는데, '@Repeatable'이 붙은 애너테이션은 여러 번 붙일 수 있다.

@Repeatable(ToDos.class)
@interface ToDo {
	String value();
}

예를 들어 '@ToDo'라는 애너테이션이 위와 같이 정의되어 있을 때, 다음과 같이 MyClass 클래스에 '@ToDo'를 여러 번 붙이는게 가능.

@ToDo("delete test code")
@ToDo("override inherited methods")
class MyClass {
	...
}

 

일반적인 애너테이션과 달리 같은 이름의 애너테이션이 여러 개가 하나의 대상에 적용될 수 있기 때문에, 이 애너테이션들을 하나로 묶어서 다룰 수 있는 애너테이션도 추가로 정의해야 한다.

@interface ToDos { //여러 개의 ToDo 애너테이션을 담을 컨테이너 애너테이션
	ToDo[] value(); // ToDo애너테이션 배열타입의 요소 선언. 이름이 반드시 value이어야 함
}
@Repeatable(ToDos.class)
@Interface ToDo {
	String value();
}

 

@Native

- 네이티브 메서드에 의해 참조되는 '상수 필드'에 붙이는 애너테이션이다. 

@Native public static final long MIN_VALUE = 0x8000000000000000L;

네이티브 메서드는 JVM이 설치된 OS의 메서드이다. 보통 C언어로 작성되어 있으며, 자바에서는 메서드의 선언부만 정의하고 구현은 안함.

그래서 추상 메서드처럼 선언부만 있고 몸통이 없다.

모든 클래스의 조상인 Object 클래스의 메서드들은 대부분 네이티브 메서드이다. 실제로 호출되는 것은 OS의 메서드이다.

 

3.4 애너테이션 타입 정의하기

새로운 애너테이션 타입을 정의하는 방법은, 다음과 같다.

엄밀히 말하면 '@Override'는 애너테이션이고 'Override'는 애너테이션의 타입이다.

+ 타입 요소 이름으로 괄호치는 것에 유의한다. 예를 들어 int count(); 이렇게 요소를 지정한다.

@interface 애너테이션이름 {
	타입 요소 이름(); //애너테이션의 요소를 선언한다.
    ...
}

 

Comments