JiwonDev

μžλ°” μ–΄λ…Έν…Œμ΄μ…˜(@Annotation)

by JiwonDev

μžλ°”μ—μ„œ μ‚¬μš©ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜ (@Annotation )은 컴파일러λ₯Ό μœ„ν•œ μΌμ’…μ˜ μ£Όμ„μœΌλ‘œ, [데이터λ₯Ό μ‘°μž‘ν•˜κ±°λ‚˜ μ½”λ“œμ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμœΌλ©°] 컴파일 κ³Όμ •κ³Ό μ‹€ν–‰κ³Όμ •μ—μ„œ μ–΄λ–»κ²Œ 좔가적인 처리 & μ»΄νŒŒμΌμ„ ν•΄μ•Ό ν•˜λŠ”μ§€ 정보λ₯Ό 쀄 수 μžˆλ‹€.

 

λ˜ν•œ κΌ­ 컴파일러 섀정이 μ•„λ‹ˆλ”λΌλ„, μ†Œν”„νŠΈμ›¨μ–΄ 개발 툴이 μ–΄λ…Έν…Œμ΄μ…˜ 정보λ₯Ό 읽어 λΉŒλ“œ 또느 λ°°μΉ˜μ‹œμ— ν•„μš”ν•œ μ½”λ“œλ₯Ό μžλ™μœΌλ‘œ 생성할 수 μžˆλ„λ‘ λ§Œλ“€ 수 μžˆλ‹€.

 

μ–΄λ…Έν…Œμ΄μ…˜μ„ 적극적으둜 μ‚¬μš©ν•˜κΈ°μ „μ—λŠ” μ΄λŸ¬ν•œ μ„€μ • 정보λ₯Ό XMLλ“±μœΌλ‘œ λ”°λ‘œ κ΄€λ¦¬ν–ˆλŠ”λ°, μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©° μžλ°” μ†ŒμŠ€μ½”λ“œμ™€ ν•¨κ»˜ 합쳐 ν•˜λ‚˜λ‘œ 관리 ν•  수 있게 λ˜μ—ˆλ‹€. λ˜ν•œ @μ–΄λ…Έν…Œμ΄μ…˜μ„ μ΄μš©ν•˜λ©΄ μ½”λ“œμƒμ— 섀정정보가 λͺ…ν™•ν•˜κ²Œ λ“€μ–΄λ‚˜μ„œ 개발자의 μ‹€μˆ˜λ₯Ό 쀄여쀀닀.

@AnnotationName

μ–΄λ…Έν…Œμ΄μ…˜μ„ μžλ°”μ—μ„œ μ œκ³΅ν•˜λŠ” [ν‘œμ€€ μ–΄λ…Έν…Œμ΄μ…˜]κ³Ό, @interface νƒœκ·Έλ₯Ό μ΄μš©ν•΄ μ–΄λ…Έν…Œμ΄μ…˜μ„ μƒˆλ‘œ λ§Œλ“€ λ•Œ μ‚¬μš©λ˜λŠ” [메타 μ–΄λ…Έν…Œμ΄μ…˜]이 μžˆλ‹€. 

ν‘œμ€€ μ–΄λ…Έν…Œμ΄μ…˜ (*κ°€ 뢙은 것은 메타 μ–΄λ…Έν…Œμ΄μ…˜)

 


# 자주 μ‚¬μš©ν•˜λŠ” ν‘œμ€€μ–΄λ…Έν…Œμ΄μ…˜

@Override

μ˜€λ°”λΌμ΄λ”©μ„ μ˜¬λ°”λ₯΄κ²Œ ν–ˆλŠ”μ§€, 컴파일 νƒ€μž„μ— 체크λ₯Ό ν•œλ‹€. 

class Parent {
	void myMethod(){~}
}

class Child extends Parent{
    // ??? μ˜€λ²„λΌμ΄λ”©μ„ ν•˜λ €λ‹€κ°€ μ‹€μˆ˜λ‘œ λ‹€λ₯Έ 이름을 μž‘μ„±ν•˜μ˜€λ‹€.
    // ν•˜μ§€λ§Œ 컴파일러 μž…μž₯μ—μ„œλŠ” 이게 μ˜€λ²„λΌμ΄λ”©μ„ ν•˜λ €κ³  ν•œκ±΄μ§€ μ•Œ 수 μ—†λ‹€.
    void myMetho(){~}    
}
class Child extends Parent{
    @Override 
    void myMetho(){~} // 컴파일 μ—λŸ¬! λΆ€λͺ¨μ—κ²Œ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” λ©”μ„œλ“œ    
}

 

@Deprecated

μ΄λ¦„λ§Œ 봐도 μ•Œ 수 μžˆλ“―μ΄, 더 이상 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것을 ꢌμž₯ν•˜λŠ” μ˜› ν•„λ“œλ‚˜ λ©”μ„œλ“œμ— 뢙인닀. μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ©΄ μ‚­μ œν•˜λ©΄ λ˜μ§€ μ•Šλƒ?κ³  생각할 수 μžˆμ§€λ§Œ μžλ°”μ—μ„œλŠ” κΈ°μ‘΄ μ•±μ˜ ν•˜μœ„ν˜Έν™˜μ„±μ„ μ œκ³΅ν•˜κΈ° μœ„ν•΄ ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œλ‹€.

@Deprecated
public int getDate(){
	return normalize().getDayOfMonth();
}

μ‹€μ œ Deprecated된 λ©”μ„œλ“œ. μ»΄νŒŒμΌμ‹œμ—λ„ 경고문이 μ˜¬λΌμ˜€μ§€λ§Œ, 보톡 IDEμ—μ„œ λ¨Όμ € μ•Œλ €μ€€λ‹€.

 

@FunctionalInterface

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ— μ‚¬μš©ν•˜λ©°, μ»΄νŒŒμΌλŸ¬κ°€ ν•¨μˆ˜ν˜•μœΌλ‘œ μ˜¬λ°”λ₯΄κ²Œ μž‘μ„±ν–ˆλŠ”μ§€ λ¬Έλ²•μ μœΌλ‘œ ν™•μΈν•œλ‹€. (ν•˜λ‚˜μ˜ μΆ”μƒλ©”μ„œλ“œλ§Œ 가지고 μžˆλŠ”κ°€?)

 

@SuppressWarnings("κ²½κ³ ")

ν•΄λ‹Ή λ©”μ„œλ“œ, ν•„λ“œμ— κ²½κ³ λ©”μ‹œμ§€κ°€ λ‚˜νƒ€λ‚˜λ„ μ»΄νŒŒμΌλŸ¬κ°€  λ¬΄μ‹œν•˜λ„λ‘ μ„€μ •ν•œλ‹€. μ—¬λŸ¬ 개λ₯Ό λ¬΄μ‹œν•˜λ €λ©΄ { "a", "b", "c" } 둜 μž‘μ„±ν•œλ‹€. ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ˜ μ‚¬μš©μœΌλ‘œ 이 κ²½κ³ λ₯Ό κ°œλ°œμžκ°€ ν™•μΈν•˜μ˜€κ³ , 였λ₯˜κ°€ μ•„λ‹ˆλΌλŠ” 것을 μ•Œλ €μ€„ 수 μžˆλ‹€.

@SuppressWarnings("unchecked")
ArrayList list = new ArrayList(); // μ œλ„€λ¦­ νƒ€μž…μ„ μ§€μ •ν•˜μ§€ μ•Šμ•˜μŒ
list.add(obj); // unchecked κ²½κ³  λ°œμƒ

 

κ·Έ μ™Έ λ‹€μ–‘ν•œ μ–΄λ…Έν…Œμ΄μ…˜μ΄ μžˆλ‹€λŠ”κ±°λ§Œ μ•Œκ³ μžˆμž.

 


# 직접 λ§Œλ“€κΈ°, 메타 μ–΄λ…Έν…Œμ΄μ…˜

@interface λ₯Ό μ΄μš©ν•˜μ—¬ 클래슀 μ •μ˜ν•˜λ“―μ΄ μƒˆλ‘œμš΄ μ–΄λ…Έν…Œμ΄μ…˜μ„ λ§Œλ“€ 수 μžˆλ‹€. java.lang.annotation.ElementType을 μ΄μš©ν•˜μ—¬ νŠΉμ • νƒ€μž…μ—λ§Œ μ μš©λ˜λ„λ‘ μ„€μ •ν•œλ‹€.

@Target(  νƒ€μž…μ§€μ •  )
@Retention(  μ–΄λ…Έν…Œμ΄μ…˜ 생λͺ…μ£ΌκΈ°  )
public @interface SuppressWarnings{
	String[] value();
    ...
}

 

@Target

μ–΄λ…Έν…Œμ΄μ…˜μ˜ μ μš©λŒ€μƒμ„ μ§€μ •ν•œλ‹€.

// 클래슀(type), ν•„λ“œ(filed), λ©”μ„œλ“œ(method)에 μ μš©κ°€λŠ₯ν•œ μ–΄λ…Έν…Œμ΄μ…˜.
@Target( {TYPE, FILED, METHOD } )
public @interface MyAnnotation{...}

// 참고둜 TYPE, FILED 등은 java.lang.annotation.ElementType 에 μ‘΄μž¬ν•˜λŠ” 섀정값이닀.
@Target( {ElementType.TYPE, ElementType.METHOD } )
public @interface MyAnnotation{...}

 


@Retention

μ–΄λ…Έν…Œμ΄μ…˜μ΄ μœ μ§€(retention)λ˜λŠ” μ‹œκΈ°, 즉 μ–΄λ…Έν…Œμ΄μ…˜μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό 지정해쀄 수 μžˆλ‹€. CLASS둜 μ§€μ •ν•˜λ©΄ λŸ°νƒ€μž„μƒμ— μ‘΄μž¬ν•˜λ‚˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λŠ” 건 λΆˆκ°€λŠ₯ν•œλ° (λ¦¬ν”Œλ ‰μ…˜ λΆˆκ°€λŠ₯, JVM의 ClassLoader κΉŒμ§€λ§Œ μ‚¬μš©κ°€λŠ₯) CLASS λ₯Ό μ“°λŠ” 일은 거의 μ—†κ³  보톡 SOURCE/RUNTIME 둜 ꡬ뢄지어 μ‚¬μš©ν•œλ‹€. 

SOURCE μ†ŒμŠ€ μ½”λ“œλ₯Ό 뢄석할 λ•Œλ§Œ 의미있고, 컴파일 이후 λ°”μ΄νŠΈ μ½”λ“œμ—λŠ” 남지 μ•ŠλŠ”λ‹€.
CLASS (κΈ°λ³Έκ°’) λ°”μ΄νŠΈ μ½”λ“œ νŒŒμΌκΉŒμ§€ μ‘΄μž¬λŠ” ν•˜λ‚˜, λ¦¬ν”Œλ ‰μ…˜μ„ μ΄μš©ν•΄μ„œ μ–΄λ…Έν…Œμ΄μ…˜ 정보λ₯Ό 얻을 μˆ˜λŠ” μ—†λ‹€. (보톡 잘 μ•ˆμ“΄λ‹€.)
RUNTIME λ°”μ΄νŠΈ μ½”λ“œ νŒŒμΌκΉŒμ§€ μ‘΄μž¬ν•˜κ³  λ¦¬ν”Œλ ‰μ…˜μ„ μ΄μš©ν•˜μ—¬ λŸ°νƒ€μž„ μ‹œμ— μ–΄λ…Έν…Œμ΄μ…˜ 정보λ₯Ό 얻을 수 μžˆλ‹€.

source - 컴파일 이후 ν΄λž˜μŠ€νŒŒμΌμ— 쑴재 X / runtime - λ°”μ΄νŠΈμ½”λ“œμ— 쑴재.

@Target(ElementType.METHOD )
@Retention(RetentionPolicy.SOURCE) // 컴파일 μ΄ν›„μ—λŠ” 없어짐.
public @interface Override{...}

//참고둜 μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μˆœμ„œλŠ” 별 상관 μ—†λ‹€.
@Documented
@Retention(RetentionPolicy.RUNTIME) // μ‹€ν–‰ 후에도 μ‚¬μš©κ°€λŠ₯(λ¦¬ν”Œλ ‰μ…˜)
@Target( TYPE )
public @interface FunctionalInterface{...}

@Documented

javadoc으둜 μž‘μ„±ν•œ λ¬Έμ„œ(html)에 ν¬ν•¨μ‹œν‚€λ €λ©΄ @Documentedλ₯Ό μ‚¬μš©ν•œλ‹€. μš°λ¦¬κ°€ 직접 μ‚¬μš©ν•  일은 거의 μ—†λ‹€.

//참고둜 μ–΄λ…Έν…Œμ΄μ…˜ μ„ μ–Έ μˆœμ„œλŠ” 별 상관 μ—†λ‹€.
@Documented
@Retention(RetentionPolicy.RUNTIME) // μ‹€ν–‰ 후에도 μ‚¬μš©κ°€λŠ₯(λ¦¬ν”Œλ ‰μ…˜)
@Target( TYPE )
public @interface FunctionalInterface{...}

 

@Inherited (상속)

ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ„ λŒ€μƒμ˜ μžμ‹κΉŒμ§€ 적용되게 ν•  λ–„ μ‚¬μš©ν•œλ‹€. 거의 μ‚¬μš©ν•  일이 μ—†λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄κΈ΄ ν•˜λ‹€.

@Inheriteed
@interface MyAnno


@MyAnno
class Parent{} // μ–΄λ…Έν…Œμ΄μ…˜ 적용됨

class Child extends Parent{} //  μ–΄λ…Έν…Œμ΄μ…˜ 적용됨.

 

@Repeatable

같은 μ–΄λ…Έν…Œμ΄μ…˜μ„ μ—¬λŸ¬κ°œ 뢙일 수 μžˆλ„λ‘ λ§Œλ“€μ–΄μ€€λ‹€. 이것도 거의 μ‚¬μš©ν•  일은 μ—†λ‹€.

@Repeatable(ToDos.class)
@interface ToDo{
	...
}

// 단, μ œλŒ€λ‘œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” ν•˜λ‚˜λ‘œ λ¬Άμ–΄μ„œ 관리할 μ»¨ν…Œμ΄λ„ˆ μ–΄λ…Έν…Œμ΄μ…˜μ„ 같이 μ •μ˜ν•΄μ•Όν•œλ‹€.
@interface ToDos{
	ToDo[] value();// μ–΄λ…Έν…Œμ΄μ…˜μ„ λ°°μ—΄νƒ€μž…μœΌλ‘œ μ„ μ–Έ. 참고둜 이름은 λ°˜λ“œμ‹œ value여야함.
    // μ–΄λ…Έν…Œμ΄μ…˜ μš”μ†Œμ˜ 이름이 value인 κ²½μš°μ—λŠ” μƒλž΅ν•˜μ—¬ μž…λ ₯ κ°€λŠ₯.
}
@ToDo("delete test codes.")
@ToDo("override inheriteed methods")
class MyClass{
	...
}

 


# μ–΄λ…Έν…Œμ΄μ…˜ νƒ€μž… μ •μ˜ν•˜κΈ°

μ–΄λ…Έν…Œμ΄μ…˜λ„ ν΄λž˜μŠ€μ™€ λ™μΌν•˜κ²Œ μ •μ˜ ν•  수 μžˆλ‹€. 단 νƒ€μž…μ„ μ •μ˜ν•  땐 λ§€κ°œλ³€μˆ˜κ°€ μ—†λŠ” μΆ”μƒλ©”μ„œλ“œλ§Œ μ΄μš©ν•  수 μžˆλ‹€. λ‹Ήμ—°νžˆ μΆ”μƒλ©”μ„œλ“œλ‘œλ§Œ μ΄λ£¨μ–΄μ ΈμžˆμœΌλ―€λ‘œ, μ˜ˆμ™Έλ₯Ό μ„ μ–Έν•˜λŠ”κ±°λ‚˜ μ œλ„€λ¦­<T>λ₯Ό μ‚¬μš©ν•˜λŠ” 건 λΆˆκ°€λŠ₯ν•˜λ‹€.

@interface μ–΄λ…Έν…Œμ΄μ…˜μ΄λ¦„{
	νƒ€μž… μš”μ†Œμ΄λ¦„(); // μΆ”μƒλ©”μ„œλ“œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.
}

@interface TestInfo{
    int count();
    static final id =100; // μ˜ˆμ™Έμ μœΌλ‘œ μƒμˆ˜λŠ” μ‚¬μš©κ°€λŠ₯ν•˜λ‹€. μƒλž΅ν•΄λ„ μƒμˆ˜λ‘œ 취급함.
    String testedBy();
    String[] testTools(); // λ°°μ—΄
    TestType testType(); // enum μ΄λ‚˜ Class도 κ°€λŠ₯ν•˜λ‹€.
    DateTime testDate(); // μžμ‹ μ΄ μ•„λ‹Œ λ‹€λ₯Έ μ–΄λ…Έν…Œμ΄μ…˜(@DataTime)을 포함할 수 μžˆλ‹€.
}

μ΄λ ‡κ²Œ μ •μ˜ν•œ μ–΄λ…Έν…Œμ΄μ…˜μ€ μ•„λž˜μ™€ 같이 μ‚¬μš©ν•  μˆ˜μžˆλ‹€. μ΄λ ‡κ²Œ 받은 정보λ₯Ό μ»΄νŒŒμΌλŸ¬λ‚˜ μ†Œν”„νŠΈμ›¨μ–΄ 개발 툴이 μ‚¬μš©ν•  수 μžˆλ‹€. 보톡은 μ–΄λ…Έν…Œμ΄μ…˜μ— μ €μž₯된 값을 λ‹€λ£¨λŠ” 일은 거의 μ—†κ³  보톡 λ§Œλ“€μ–΄μ§„ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ•„λž˜μ™€ 같이 μ‚¬μš©ν•˜κ²Œ λœλ‹€.

 

@ default κ°’

μ μš©μ‹œ 값을 μ§€μ •ν•˜μ§€ μ•Šμ•˜μ„ λ–„ μ‚¬μš©ν•  수 μžˆλŠ” 기본값을 지정할 수 μžˆλ‹€. λ‹Ήμ—°ν•œκ±°μ§€λ§Œ default λ©”μ„œλ“œλŠ” μ‚¬μš© λΆˆκ°€λŠ₯ν•˜λ‹€.

@interface TestInfo{
    int count() default 1 // κΈ°λ³Έκ°’ 1
    // λ‹Ήμ—°ν•œκ±°μ§€λ§Œ κΈ°λ³Έκ°’μœΌλ‘œ null을 쀄 μˆ˜λŠ” μ—†λ‹€.
    
    int id = 100; // μ΄λŠ” static final int id=100으둜 λ³€ν™˜λœλ‹€. 즉 μƒμˆ˜μ΄λ‹€.
}

 

@ value μš”μ†Œ

μš”μ†Œμ˜ 이름이 valueμΌλ•ŒλŠ” μ‚¬μš©μ‹œ 이름을 μƒλž΅ν•  수 μžˆλ‹€.

@interface TestInfo{
	String value();
}

@TestInfo("μ΄λ ‡κ²Œ λ°”λ‘œ μ‚¬μš©ν• μˆ˜μžˆμŒ") // value="~"둜 취급됨.
class NewClass {...}

 

@ μš”μ†Œ νƒ€μž…μ΄ 배열일 λ•Œ

κ΄„ν˜Έ { } λ₯Ό μ‚¬μš©ν•΄μ„œ μž…λ ₯ν•˜λ©°, 값이 ν•˜λ‚˜ 인경우 κ΄„ν˜Έλ₯Όμƒλž΅ν•΄λ„ λœλ‹€.

@Test(testTools= {"JUnit", "AutoTester"} )// λ°°μ—΄ νƒ€μž…
@Test(testTools ="JUnit")// 값이 ν•˜λ‚˜μΌ 땐 μƒλž΅κ°€λŠ₯
@Test(testTools = {})// 쀄 값이 없을땐 λΉˆκ΄„ν˜Έλ₯Ό μ€˜μ•Όν•¨. testTools; 이런거 μ•ˆλ¨.

 

@ μ–΄λ…Έν…Œμ΄μ…˜μ˜ κΈ°λ³Έ μΆ”μƒλ©”μ„œλ“œ

java.lang.annotation.Annotation 은 λͺ¨λ“  μ–΄λ…Έν…Œμ΄μ…˜μ˜ 쑰상 μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€. ν•˜μ§€λ§Œ extends둜 상속은 ν•  μˆ˜λŠ” μ—†λ‹€.(ν•˜λ©΄ 컴파일 μ—λŸ¬) κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  μ΄λ ‡κ²Œ λ§Œλ“  μ΄μœ λŠ”, Object의 λ©”μ„œλ“œμ²˜λŸΌ λͺ¨λ“  μ–΄λ…Έν…Œμ΄μ…˜μ΄ 가지고 μžˆλŠ” μΆ”μƒλ©”μ„œλ“œλ₯Ό μ œκ³΅ν•˜κΈ° μœ„ν•΄μ„œμ΄λ‹€.

package java.lnag.annotation;

public interface Annotation{
    boolean equals(Object obj);
    int hashCode();
    String toString();
    
    Class<? extends Annotation> annotationType(); // μ–΄λ…Έν…Œμ΄μ…˜ νƒ€μž…λ°˜ν™˜
}

 

@ Marker μ–΄λ…Έν…Œμ΄μ…˜

κ±°μ°½ν•œκ±΄ μ•„λ‹ˆκ³ , μš”μ†Œμ—†μ΄ λΉ„μ–΄μžˆλŠ” μ–΄λ…Έν…Œμ΄μ…˜μ„ μ˜λ―Έν•œλ‹€. 이름 κ·ΈλŒ€λ‘œ νŠΉμ • ν•„λ“œ, λ©”μ„œλ“œλ₯Ό ꡬ뢄할 마컀둜 쓰인닀.

@Target(METHOD)
@Retention(SOURCE)
public @interface Test{} // 마컀 μ–΄λ…Έν…Œμ΄μ…˜

@Test // ν…ŒμŠ€νŠΈ ν‘œμ‹œμš©λ„.
public void method(){...}

@Deprecated // μ‚¬μš©ν•˜λ©΄ κ²½κ³ λ„μš°λŠ” μš©λ„.
public int getDate(){...}

λΈ”λ‘œκ·Έμ˜ 정보

JiwonDev

JiwonDev

ν™œλ™ν•˜κΈ°