🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
형식은 기존의 인터페이스과 동일하고
차이점은 @
을 사용하느냐에 있다.
@interface 애너테이션 이름 {
타입 요소이름() ; // 요소 선언
...
..
}
/*
일반적인 interface의 모습
interface 인터페이스 {
타입 요소이름();
...
..
}
*/
@애너테이션
: 애너테이션으로 사용되는 것이렇게 애너테이션 내에 메서드가 선언되는데
애너테이션의 메서드는 추상 메서드이고
이를 " 애너테이션의 요소(Element) "라고 한다.
(단, 인터페이스처럼 상수는 정의할 수 있을지라도 디폴트 메서드는 정의할 수 없다.)
enum TestType { FIRST, FINAL }
/* 내부 선언 메서드(요소)들은 여러가지 타입들로 정의될 수 있음 */
@interface Test {
int count(); // 정수
String testedBy() ; // 문자열
String[] testTools() ; // 문자열 배열
TestType testType(); // Enum
DateTime testDate(); // 다른 애너테이션
}
@interface DateTime {
String yymmdd() ;
String hhmmss() ;
}
위처럼
요소들을 다양한 타입으로 정의할 수 있는 것을 알 수 있다.
이렇게 생성한 애너테이션을 사용하려면
아래와 같이 사용하면 된다.
( 순서는 상관 없음. )
@Test(
count = 3,
testedBy = "Jung",
testTools = {"JUnit", "AutoTester"},
testType = TestType.FIRST
testDate = @DateTime(yymmdd="", hhmmss="")
)
// 호출 방식은 " 애너테이션.요소() " 로 값을 호출한다.
// Test.count() → 3
@Test
public class NewTest {
... // Test 애너테이션 사용가능
}
요소의 타입이 배열일 경우에는
중괄호 {}
를 사용하면 된다.
/*
요소의 타입이 배열이면
앞서 여러가지 값을 다룰 때 사용했던 것처럼
`{}`을 사용해서 지정하면 된다.
*/
@interface Test {
String[] Tools();
}
@Test(Tools = {"JUnit", "AutoTester"})
//@Test(Tools = "JUnit") 하나도 가능 - "{}" 생략 가능
/* ★ 값이 없을 땐 "{}"를 생략할 수 없다 */
// @Test(Tools = {})
public class NewTest {...}
단, 모든 요소의 값을 지정해주어야 한다는 것을 주의해야한다.
만약 한 가지 요소는 매번 동일한 값을 사용할 때,
매번 작성해주는 것은 비효율적이다.
그런 경우,
기본값 (default)도 지정해 줄 수 있다.
( null을 제외하고 모든 리터럴 가능 )
@interface Test {
int count() default 3;
String testedBy() default "Jung" ;
String[] testTools() default {"JUnit", "AutoTester"};
}
@Test // 이렇게 기본값이 모두 있는 경우엔 애너테이션만 달아줘도 되고
@Test(testTools ={}) // 이렇게 원하는 것만 골라서 값을 지정해줘도 된다.
public class NewTest {...}
또한
이전 게시물에서도 알아봤던 value
의 경우인데
" 애너테이션의 요소가 단 하나뿐이고 이름 : value
인 경우 "는
애너테이션 적용 시,
요소 이름을 생략하고 값만 적어도 된다.
@interface Test {
String value();
}
@Test("passed")
public class NewTest {...}
이 value가 " 배열인 경우 " 에도 동일하다.
//@SuppressWarnings 의 경우
@interface SuppressWarnings {
String[] value();
}
//@SuppressWarnings(value = {"deprecation", "unchecked"})
@SuppressWarnings({"deprecation", "unchecked"})
public class NewClass {...}
※ TIPS
- class에 대해
클래스이름.class ;
로 클래스 객체를 만들 수 있다.
▶ 애너테이션에 대한 정보도 담겨 있다! ( 유효하지 않은 애너테이션은 무시 )@Test class Test { Class<Test> cls = Test.class ; // cls라는 Test 클래스 타입 매개변수 생성 }
- 클래스 객체에서
getAnnotation( 특정 애너테이션 )
/getAnnotations()
메서드 등으로 애너테이션 정보만 가져올 수 있다.@SuppressWarnings("1111") // 유효하지 않아서 getAnnotations 메서드 사용시 무시한다. @Deprecated @Test( count = 3, testedBy = "Jung", testTools = {"JUnit", "AutoTester"}, testType = TestType.FIRST ) class Test { Class<Test> cls = Test.class ; Test anno = cls.getAnnotation(Test.class) ; // 위와 같이 .class를 통해 애너테이션 클래스 객체를 생성 System.out.println(anno.testedBy()); // Jung 출력 System.out.println(anno.testType()); // FIRST 출력 Annotation[] annoArr = cls.getAnnotations() ; // 모든 애너테이션을 배열로 가져온다. for( Annotation a : annoArr) { System.out.println(a) ; } /* @java.lan.Deprecated() @Test(count=3, testedBy=Jung, testTools = [JUnit, AutoTester], testType=FIRST) */ }
사실 모든 애너테이션에게는 조상이 있다.
바로 java.lang.annotation
패키지에 정의되어 있는
Annotation
이다.
그래서 모든 애너테이션의 조상이기는 하나
애너테이션의 특성 상
" 상속이 불가능 "하기 때문에
조상으로 지정할 수 없다.
/* 에러 발생!! 불가능!! */
@interface Test extends Annotation {
...
}
앗 그런데 잠깐!
지금까지 애너테이션을 살펴봤을 때,
가장 많이 보인 키워드가 있다.
바로
" interface "
그럼 implements
는 안되는가?
심지어 implements도 불가능하다.
이 애너테이션에 extends
나 implements
를 시도했다가는
이런 메세지와 함께 실패를 맛보게 된다.
Annotation type declaration cannot have explicit superinterfaces
Annotation type declaration cannot have an explicit superclass
" 그럼 도대체 진짜 interface는 뭐가 있는가 ?! "
그렇다.
java.lang.annotation
패키지에 정의되어 있는
Annotation
만 일반적인 인터페이스이다.
심지어는 애너테이션도 아니다..
그냥 조상일 뿐인 본인(?)만 인터페이스인 것이다...
실제 Annotation
인터페이스는 아래와 같이 구성되어 있다.
package java.lang.annotation;
public interface Annotation {
/* 추상 메서드 */
boolean equals( Object obj );
int hashCode() ;
String toString();
Class<? extends Annotation> annotationType(); // 애너테이션의 타입을 반환한다.
}
하지만 조심해야할 것은
상속이 불가능하다고 자손이 아닌 것이 아니고
모든 애너테이션은 Annotation
의 자손이기 때문에
위에 보이는
equals
/ hashCode
/ toString
과 같은 메서드들을
여간 인터페이스들과 다를 바 없이
모든 애너테이션 객체에서 호출하는 것이 가능 하다.
" 값을 지정할 필요가 없는 경우 "
요소가 하나도 정의되지 않은 애너테이션
Serializable
이나 Cloneable
인터페이스 처럼
요소가 하나도 정의되지 않은 애너테이션을 가르킨다.
( 애너테이션을 달 때, 아무 값도 입력하지 않음 )
보통
값이 필요없더라도
프로그램 내부에 " 애너테이션이 달려있는 코드에 대한 정보를 전달하는 역할 "로 쓰인다.
1. 요소의 타입은 【 기본형 | String | enum | 애너테이션 | 클래스(Class) 】만 허용
* Class라 함은 '설계도 객체'를 뜻한다. (java.lang 패키지와 유용한 클래스 게시글 참고)
2. 추상메서드 괄호 안에 매개변수를 선언할 수 없다.
3. 예외를 선언할 수 없다.
4. 요소를 타입 매개변수로 정의할 수 없다.
*지네릭 타입 등으로도 사용할 수 없다.
@interface AnnoTest {
ArrayList<T> list() ; // 타입 매개변수로 요소가 쓰일 수 없다.
}