Annotation
: 프로그램 소스코드 안에서 다른 프로그램을 위한 정보를 제공하는 주석처럼 사용되는 기술을 말한다.
프로그램에 영향을 미치지 않으며 프로그램에게 유용한 정보를 제공한다.
- 종류
1. 표준애너테이션 : 자바에서 기본적으로 제공하는 애너테이션
2. 메타애너테이션 : 어노테이션에 붙이는 어노테이션. 어노테이션을 정의하는 데 사용하며 어노테이션의 적용대상 또는 어노테이션을 유지하는 시간 등을 규정한다.
- 애너테이션 요소의 규칙
1. 요소타입은 기본형, String, enum, annotation, Class만 허용된다.
2. ()안에 매개변수를 선언할 수 없다.
3. 예외를 선언할 수 없다.
4. 요소타입에 제너릭타입글자를 사용할 수 없다.
- 사용법
@interface 애너테이션 이름 {
요소타입 타입요소이름(); // 반환값이 있고 매개변수는 없는 추상메서드의 형태
...
}
package kr.or.ddit.basic;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
* Annotation 에 대하여...
*
* 프로그램 소스코드 안에서 다른 프로그램을 위한 정보로 미리 약속된 형식으로 포함시킨 것(JDK1.5부터 지원)
*
* 주석처럼 프로그램에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공함.
*
* 종류 : 1. 표준애너테이션
* 2. 메타애너테이션(애너테이션을 위한 애너테이션, 즉 애너테이션을 정의할 때 사용하는 애너테이션)
*
* 애너테이션 타입 정의하기
* @interface 애너테이션 이름 {
* 요소타입 타입요소이름(); // 반환값이 있고 매개변수는 없는 추상메서드의 형태
* ...
* }
*
* 애너테이션 요소의 규칙
* 1. 요소타입은 기본형, String, enum, annotation, Class만 허용된다.
* 2. ()안에 매개변수를 선언할 수 없다.
* 3. 예외를 선언할 수 없다.
* 4. 요소타입에 제너릭타입글자를 사용할 수 없다.
*/
@Target({ElementType.METHOD, ElementType.TYPE}) // 적용가능 대상 지정함
@Retention(RetentionPolicy.RUNTIME) // 유지되는 기간 지정함.
public @interface PrintAnnotation {
String value() default "-"; // 디폴트로 -값이 지정됨
int count() default 20;
}
package kr.or.ddit.basic;
public class Service {
// 아무것도 안 넣기에 value -, count 20이 디폴트로 주어진 것
@PrintAnnotation
public void method1() {
System.out.println("메서드1이 호출되었습니다.");
}
@PrintAnnotation(value = "%")
public void method2() {
System.out.println("메서드2이 호출되었습니다.");
}
@PrintAnnotation(value = "#", count = 25)
public void method3() {
System.out.println("메서드3이 호출되었습니다.");
}
}
- PrintAnnotation 확인 예시
package kr.or.ddit.basic;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class AnnotationTest {
public static void main(String[] args) {
Method[] methodArr = Service.class.getDeclaredMethods();
for (Method m : methodArr) {
System.out.println("메서드 명 : " + m.getName());
Annotation[] annos = m.getDeclaredAnnotations();
for (Annotation anno : annos) {
if(anno.annotationType().getSimpleName().equals("PrintAnnotation")) {
PrintAnnotation printAnno = (PrintAnnotation) anno;
int count = printAnno.count();
String value = printAnno.value();
for(int i=0; i<count; i++) {
System.out.print(value);
}
}
}
System.out.println(); // 줄바꿈 처리
}
}
}
리플렉션 사용
어노테이션 정보를 접근해 보기 위해 리플렉션을 사용한다.
- 순서
1. 클래스 오브젝트를 생성하여 클래스의 정보를 가져옴
2. 클래스의 메타데이터 가져옴
- Java Reflection
1. 리플렉션은 런타임 시점에 클래스 또는 멤버변수, 메서드, 생성자 등에 대한 정보를 가져오거나 수정할 수 있고, 새로운 객체를 생성하거나 메서드를 실행할 수 있다. (컴파일 시점에 해당정보를 알 수 없는 경우(소스코드의 부재)에 유용하게 사용될 수 있다.)
2. 리플렉션 API는 java.lang.reflect 패키지와 java.lang.Class를 통해 제공된다.
3. java.lang.Class의 주요 메서드
- getName(), getSuperClass(), getInterfaces(), getModifiers() 등.
4. java.lang.reflect 패키지의 주요 클래스
- Field, Method, Constructor, Modifier 등.
- Class 오브젝트(클래스정보를 담고 있는 객체)를 생성하기
package kr.or.ddit.ref;
/**
* Class 오브젝트(클래스정보를 담고 있는 객체)를 생성하기
*/
public class T01ClassObjectCreationTest {
/*
* Java Reflection 에 대하여...
*
* 1. 리플렉션은 런타임 시점에 클래스 또는 멤버변수, 메서드, 생성자 등에 대한 정보를 가져오거나 수정할 수 있고,
* 새로운 객체를 생성하거나 메서드를 실행할 수 있다.
* (컴파일 시점에 해당정보를 알 수 없는 경우(소스코드의 부재)에 유용하게 사용될 수 있다.)
* 2. 리플렉션 API는 java.lang.reflect 패키지와 java.lang.Class를 통해 제공된다.
* 3. java.lang.Class의 주요 메서드
* - getName(), getSuperClass(), getInterfaces(), getModifiers() 등.
* 4. java.lang.reflect 패키지의 주요 클래스
* - Field, Method, Constructor, Modifier 등.
*/
public static void main(String[] args) throws ClassNotFoundException {
// 방법1 : Class. forName(클래스 이름) 메서드 이용하기
// 클래스 이름에 대한 정보를 klass에 저장
Class<?> klass = Class.forName("kr.or.ddit.ref.T01ClassObjectCreationTest");
// 방법2 : getClass() 메서드 이용하기
klass = new T01ClassObjectCreationTest().getClass();
// 방법3 : .class 이용하기
klass = T01ClassObjectCreationTest.class;
}
}
- 클래스의 메타데이터 가져오기 - 예시 1
package kr.or.ddit.ref;
import java.io.Serializable;
public class SampleVO implements Serializable{
private String id;
protected String name;
public int age;
public SampleVO(String id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public SampleVO() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package kr.or.ddit.ref;
import java.lang.reflect.Modifier;
/**
* Class의 메타데이터 가져오기
*/
public class T02ClassMetadataTest {
public static void main(String[] args) {
// 클래스 오브젝트 생성하기
Class<?> clazz = SampleVO.class;
System.out.println("심플클래스명 : " + clazz.getSimpleName());
System.out.println("클래스명 : " + clazz.getName());
System.out.println("상위 클래스명 : " + clazz.getSuperclass().getName());
// 패키지 정보 가져오기
Package pkg = clazz.getPackage();
System.out.println("패키지 정보 : " + pkg.getName());
System.out.println();
// 해당 클래스에서 구현하고 있는 인터페이스 목록 가져오기
Class<?>[] interfaces = clazz.getInterfaces();
System.out.println("인터페이스 목록 => ");
for (Class<?> inf : interfaces) {
System.out.println(inf.getName() + " | ");
}
System.out.println();
// 클래스의 접근제어자 정보 가져오기
int modFlag = clazz.getModifiers();
System.out.println("접근제어자 정보 : " + Modifier.toString(modFlag));
}
}
- 클래스의 메타데이터 가져오기 - 예시 2
package kr.or.ddit.ref;
import java.io.Serializable;
import kr.or.ddit.basic.PrintAnnotation;
public class SampleVO implements Serializable{
private String id;
protected String name;
public int age;
public SampleVO(String id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public SampleVO() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
@PrintAnnotation
public void setName(String name) throws Exception{
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package kr.or.ddit.ref;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 클래스에 선언된 메서드의 메타정보 가져오기
*/
public class T03MethodMetadataTest {
public static void main(String[] args) throws ClassNotFoundException {
// Class 객체 생성
Class<?> klass = Class.forName("kr.or.ddit.ref.SampleVO");
// 클래스에 선언된 모든 메서드 정보 가져오기
// 메소드 타입의 배열로 가져오게 됨.
Method[] methodArr = klass.getDeclaredMethods();
for (Method m : methodArr) {
System.out.println("메서드 명 : " + m.getName());
System.out.println("메서드 리턴타입 : " + m.getReturnType());
// 해당 메서드의 접근제어자 정보 가져오기
int modFlag = m.getModifiers();
System.out.println("메서드 접근제어자 : " + Modifier.toString(modFlag));
System.out.println();
// 해당 메서드의 파라미터 정보 가져오기
Class<?>[] paramArr = m.getParameterTypes();
System.out.println("메서드 파라미터 타입 => ");
for (Class<?> clazz : paramArr) {
System.out.println(clazz.getName() + " | ");
}
System.out.println();
// 해당 메서드에서 던지는 예외타입 가져오기
Class<?>[] exTypeArr = m.getExceptionTypes();
System.out.println("메서드에서 던지는 예외타입 목록 : ");
for (Class<?> clazz : exTypeArr) {
System.out.println(clazz.getName() + " | ");
}
System.out.println();
// 해당 메서드에 존재하는 Annotation 타입정보
Annotation[] annos = m.getDeclaredAnnotations();
System.out.println("Annotation 타입 => ");
for (Annotation anno : annos) {
System.out.println(anno.annotationType().getName() + " | ");
}
System.out.println();
System.out.println("-----------------------------------------------------");
}
}
}
'자바' 카테고리의 다른 글
[Java 고급] 10장 Thread상태, Thread 예시2 (1) | 2024.01.29 |
---|---|
[Java 고급] 9장 Process와 Thread 예시1 (1) | 2024.01.27 |
[Java 고급] 7.5장 Test (0) | 2024.01.27 |
[Java 고급] 7장 enum (1) | 2024.01.27 |
[Java 고급] 6장 제한된 타입 파라미터 문법, 와일드카드 (1) | 2024.01.27 |