- 지네릭스
- 열거형
- 애너테이션
자바를 개발한 사람들은 소스코드에 대한 문서를 따로 마드기보다 소스코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각했다. 그래서 소스코드의 주석에 소스코드에 대한 정보를 저장하고, 소스코드의 주석으로부터 HTML을 생성해내는 프로그램을 만들어서 사용했다.
주석 안에 소스코드들에 대한 설명들이 있고, 그 안에 @
이 붙은 태그 들이 있다. 미리 정의된 태그들을 이용해서 주석 안에 정보를 저장하고, javadoc.exe라는 프로그램을 통해 이 정보를 읽어서 문서를 작성하는데 사용한다.
이 기능을 응용하여, 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 바로 애너테이션이다. 애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점이 있다.
예로) @Test 어노테이션은 메소드위에 붙어 이 메서드를 테스트
한다. 라는것을 테스트 프로그램에게 알리는 역할을 할 뿐, 메서드가 포함된 프로그램 자체에는 아무런 영향을 미치지 않는다. 주석처럼 존재하지 않는 것이나 다름 없다.
@Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
public void method(){
...
}
해당 프로그램에 미리 정의된 종류와 형식으로 작성해야만 의미가 있다. JDK에서 제공하는 표준 애너테이션은 주로 컴파일러를 위한 것으로 컴파일러에게 유용한 정보를 제공한다. 그리고 새로운 애너테이션을 정의할 떄 사용하는 메타 애너테이션을 제공한다.
자바에서 기본적으로 제공하는 애너테이션들은 몇 개 없다. 이 들의 일부는 메타 애너테이션
으로 애너테이션을 정의하는데 사용되는 애너테이션의 애너테이션이다.
메서드 앞에만 붙일 수 있는 애너테이션으로, 조상의 메서드를 오버라이딩 하는 것이라는 걸 컴파일러에게 알려주는 역할을 한다. 오버라이딩 시 메서드의 이름을 잘못 적는 경우가 발생할 수 있으며, 이를 컴파일러는 그저 새로운 이름의 메서드가 추가된 것으로 인식한다. 실행 시에도 오류가 발생하지 않고 조상의 메서드가 호출되므로 어디서 잘못되었는지 알아내기 어렵다.
class Child extend Parent{
@Override
void parentMethod(){
...
}
}
위의 코드와 같이 메서드 앞에 @Override라고 애너테이션을 붙이면, 컴파일러가 같은 이름의 메서드가 조상에 있는지 확인하고 없으면, 에러메시지를 출력한다.
새로운 기능이 추가될 때 기존의 부족했던 기능이 개선되기도 한다. 이 과정에서 기존의 기능을 대체할 것들이 추가되어도, 이미 여러 곳에서 사용되고 있을지 모르는 기존의 것들을 함부로 삭제할 수 없다. 그래서 더 이상 사용되지 않는 필드나 메서드에 @Depracated 애너테이션을 붙인다. 이 애너테이션이 붙은 대상은 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미이다.
해당 애너테이션이 붙은 대상을 사용하지 않도록 권할 뿐 강제성은 없다. ( 실행은 된다. )
함수형 인터페이스
를 선언할 때, 이 애너테이션을 붙이면 컴파일러가 함수형 인터페이스
를 올바르게 선언했는지 확인하고, 잘못된 경우 에러르 ㄹ발생시킨다. 필수는 아니다.
컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해준다. 경고메시지의 종류는 여러가지 가 있으며 이러한 경고메시지의 종류를 지정하여 억제해줄 수 있다.
버전이 올라가며 계속 경고메시지의 종류가 추가되는 중이다.
메서드에 선언된 가변인자의 타입이 non-reifiable타입일 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 unchecked
경고가 발생한다. 해당 코드에 문제가 없다면 이 경고를 억제하기 위해 해당 애너테이션을 사용해야 한다.
메타 애너테이션은 애너테이션을 위한 애너테이션 즉, 애너테이션에 붙이는 애너테이션으로 애너테이션을 정의할 때 애너테이션의 적용대상이나 유지기간등을 지정하는데 사용된다.
애너테이션이 적용가능한 대상을 지정하는데 사용된다. 여러개의 값을 지정할 때는 배열에서처럼 괄호{}를 사용해야 한다.
애너테이션이 유지되는 기간을 지정하는데 사용된다. 유지 정책의 종류는 SOURCE,CLASS,RUNTIME 등이 있다.
애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
애너테이션이 자손 클래스에 상속되도록 한다. @Inherited가 붙은 애너테이션을 조상클래스에 붙이면, 자손 클래스도 이 애너테이션이 붙은 것과 같이 인식된다.
보통은 하나의 대상에 한 종류의 애너테이션을 붙이는데 해당 애너테이션이 붙은 애너테이션은 여러번 붙일 수 있다.
네이티브 메서드에 의해 참조되는 상수 필드
에 붙이는 애너테이션이다.
새로운 애너테이션을 정의하는 방법은 아래와 같다. @
기호를 붙이는 것을 제외하면 인터페이스를 정의하는 것과 동일하다.
@interface 애너테이션이름{
타입 요소이름();
...
}
@Override는 애너테이션이고 Override는 애너테이션 타입이다.
애너테이션 내에 선언된 메서드를 애너테이션의 요소(element)
라고 한다. 애너테이션의 요소는 반환값이 있고 매개변수는 추상 메서드의 형태를 가지며, 상속을 통해 구현하지 않아도 된다. 다만, 애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해주어야 한다. 요소의 이름도 같이 적어주므로 순서는 상관없다.
@interface TestInfo{
int count();
String testedBy();
String[] testTools();
TestType testType(); //enum TestType {FIRST,FINAL}
DateTime testDate(); // 자신이 아닌 다른 애너테이션을 포함할 수 있다.
}
@interface DateTime{
String yymmdd();
String hhmmss();
}
@TestInfo(
count = 3,testedBy = "Kim",
testTools = {"JUnit","AutoTester"},
testType = TestType.FIRST,
testDate = @DateTime("160101","235959"}
)
public class NewClass{...}
애너테이션의 각 요소는 기본값을 가질 수 있으며, 기본값이 있는 요소는 애너테이션을 적용할 때 값을 지정하지 않으면 기본값이 사용된다.
@interface TestInfo{
int count() defualt 1; //기본값 1
}
@TestInfo // @TestInfo(count=1)과 동일
public class NewClass{...}
애너테이션의 요소가 오직 하나뿐이고 이름이 value인 경우, 애너테이션을 적용할 때 요소의 이름을 생략하고 값만 적어도 된다. 요소의 타입이 배열인 경우, 괄호{}를 사용해서 여러개의 값을 지정할 수 있다. 기본값 지정시에도 괄호{}를 사용할 수 있다. (요소의 타입이 배열일 때도 요소의 이름이 value이면, 요소의 이름이 생략할 수 있다. )
모든 애너테이션의 조상은 Annotation이다. 그러나 애너테이션은 상속이 허용되지 않으므로 아래와 같이 명시적으로 Annotation을 조상으로 지정할 수 없다.
값을 지정할 필요가 없는 경우, 애너테이션의 요소를 하나도 정의하지 않을 수 있다. 요소가 하나도 정의되지 않은 애너테이션을 마커 애너테이션이라고 한다.