Annotation, Reflection
✅ 메타 정보 & JAVA Annotation
일상 세계의 다양한 측면에 대한 보조 정보
자바 프로그램의 추가적인 정보를 주는 메타 데이터
@ 사용
☑️ 종류
Custom annotation
Built-in annotation
- Meta annotation
어노테이션에 대한 메타 데이터 - general purpose annotation
- override
- override
☑️ 용도
✔️ 컴파일 타임 체크 및 오류 검출
✔️ JAVA 코드 문서화
✔️ 런타임 추가 기능 처리 ➡️ 메타 프로그래밍에 사용
✔️ 컴파일 타임 체크 및 오류 검출
오류가 있는지 없는지 검출하는 용도
@Override
부모 클래스 메소드가 없으면 error발생
그래서 만약 Override안 써도 동작은 하지만,
Override쓰면 부모에게 없는 메소드 참조했을 때 error을 띄워 검증해 준다.
@FunctionalInterface
람다식에서
메소드 1개를 초과하면 error발생, 개발자에게 알려준다.
@Deprecate
문제가 생길 수 있는 메소드라는 뜻
찍 그어서 경고문을 표시해준다. 사용하지 않는게 좋을텐데?
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
// ✅ Customer.java
public class Customer implements Serializable {
@Deprecated
public int calculatePrice(int price){
this.bonusPoint += price * bonusRatio;
return price;
}
}
// ✅ GoldCustomer.java
//extends Customer
public class GoldCustomer extends Customer{
@Override
public int calculatePrice(int price) {
price -= price * discountRatio;
this.bonusPoint += price * bonusRatio;
return price;
}
}
// ✅ StringNum.java
@FunctionalInterface
//이것은 함수형 인터페이스라는 것을 알리기
//메소드가 1개만 있어야지, 2개 이상 되면 빨간줄
public interface StringNum {
void printString(String s);
}
✔️ JAVA 코드 문서화
메소드에 대해서 설명해주기
@ Params 및 @return
메소드가 어떤 parameter을 받고 어떤 값을 return하는지 설명해주기
1
2
3
4
5
6
7
8
9
/**
*
* @param price int 물건의 가격을 param으로 받아요
* @return int 최종 계산된 가격을 반환
*/
public int calculatePrice(int price){
this.bonusPoint += price * bonusRatio;
return price;
}
@ throws
이 메소드가 에러를 던진다면, 어떤 에러를 throw하는지 설명해주기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @param fileName 읽을 파일의 이름
* @return str 파일을 읽은 결과
* @throws IOException 파일을 찾을 수 없는 경우 발생
*/
public static String readFile(String fileName) throws IOException {
// 파일 읽기 로직
StringBuilder sb = new StringBuilder();
try(FileReader fis = new FileReader("")){
int data;
while ((data = fis.read()) != -1) {
sb.append((char) data);
}
}
return sb.toString();
}
✔️ 런타임 추가 기능 처리 ➡️ 메타 프로그래밍에 사용
✅ 사용자 정의 annotation 만들기
- 메타 어노테이션
- 어노테이션 정의
- 어노테이션 속성
어노테이션은 메소드가 없다!
@Retention
소스 파일 ➡️ 컴파일 ➡️ 클래스 파일 ➡️ JVM ➡️ run
annotation 유지 기간
- source: 소스 파일에는 존재하고 클래스 파일에는 존재하지 않는다
- class: 클래스 파일에만 존재하고 실행시에는 사용 불가하다.
컴파일할 때 까지는 존재한다.
실제로 프로그램 돌아갈 때는 적용 안 됨
기본값 - runtime: 클래스 파일에 존재하고, 실행시에도 존재합니다.
제일 긴 시간동안 존재
@Target
annotation 적용 대상
예를 들어 override는 메소드에만 적용
functionalInterface는 class에만 적용
@Documented
annotation이 javadoc에 나타나게 된다.
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
31
32
33
34
//MyAnnotation.java
//Annotation 어떻게 쓸지 정의한다.
@Retention(RetentionPolicy.RUNTIME) // runtime동안 annotation적용
@Target(ElementType.METHOD) //메소드에만 annotation적용
//@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR}) //메소드, 필드, 생성자에 annotation적용
//이런식으로 Target으로 annotation어디에 적용할지 결정할 수 있다.
@Documented
public @interface MyAnnotation {
//annotation에서는 field적용할 때 (), default 붙인다.
String name();
int count() default 0;
}
//customer.java
public class Customer implements Serializable {
//method에 MyAnnotation으로 설명해준다.
@MyAnnotation(name= "똑같은가 확인")
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj instanceof Customer){
Customer customer = (Customer) obj;
return customer.customerID == this.customerID;
}
else {
return false;
}
@MyAnnotation(name="가격 계산하기 메소드") //annotation으로 메소드 이름 정해주기
//calculatePrice에 대한 설명을 MyAnnotation에 써준다.
public int calculatePrice(int price){
this.bonusPoint += price * bonusRatio;
return price;
}
}
✅ 메타 프로그래밍
프로그램을 짠 코드를 데이터로 보고 프로그래밍을 하는 것
메타 정보를 가지고 와서 프로그래밍에 적용하는 것
- Java Custom Annotation
기본 외 직접 정의한 Annotation - Java Reflection & Class
런 타임 때, 해당 클래스 메소드와 변수에 접근 가능
☑️ Java Reflection, Class 클래스
Java Reflection으로 메타 데이터 가져오기 가능하다.
클래스의 클래스를 정의
생성자를 타입으로 정의하고 getConstructors()
로 메타데이터 얻기 가능
필드도 타임으로 정의하고 getFields()
로 메타데이터 얻기 가능
메소드도 타임으로 정의하고 getMethods()
로 메타데이터 얻기 가능
Reflection으로 함수 호출도 가능하다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//annotation
@Retention(RetentionPolicy.RUNTIME) //실제 동작하는 동안에도 annotation 실행되어야 함
@Target(ElementType.METHOD) //메소드에 적용되는 annotation
public @interface Repeat {
int value();
}
//MyClass.java
public class MyClass {
@Repeat(value = 20)
public void printMessage() {
System.out.println("Hello, world!");
}
@Repeat(value = 10)
public void foo() {
System.out.println("This is another method.");
}
}
//AnnotationTest.java
public class AnnotationTest {
public static void main(String[] args) {
MyClass myObj = new MyClass();
AnnotationUtils.executeMethodsByRepeatAnnotation(myObj);
}
}
//AnnotationUtils.java
public class AnnotationUtils {
//Annotation정보를 가지고 메소드를 실행하는 메소드
//모든 객체를 받을 수 있어 parameter이 object
public static void executeMethodsByRepeatAnnotation(Object object) {
//💡 메타 프로그래밍
Class clazz = object.getClass();
//메소드를 가져와서 배열에 저장
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
//메소드에 붙은 annotations 배열로 가져오기
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
//내가 가져온 annotation이 Repeat라는 annotation안에 있다면
if (annotation instanceof Repeat) {
//value로 개수 세기
Repeat repeatAnnotation = (Repeat) annotation;
int repeatCount = repeatAnnotation.value();
for (int i = 0; i < repeatCount; i++) {
try {
//invoke하는 reflection 실행
method.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}