네이버클라우드 AIaaS 개발자 양성과정 1기/DBMS, SQL, JDBC, Servlet
[Java] 예제 소스 정리 - Annotation
끈기JK
2023. 2. 28. 09:23
com.eomcs.annotation
예제 소스 정리
annotation
com.eomcs.annotation.ex1
애노테이션 사용
package com.eomcs.annotation.ex1;
//=> 클래스, 필드, 메서드, 로컬 변수 선언에 붙이는 특별한 주석이다.
//=> 다른 주석과 달리 컴파일이나 실행할 때 추출할 수 있다.
//=> 애노테이션 문법이 도입되기 전에
// 일반 주석에 특별한 문법을 포함시켜 사용했던 doclet 이라는 기술이 있었다.
//=> 일반 주석과 달리 '프로퍼티명=값' 형태로 값을 다룰 수 있다.
//=> 사용법
// - 애노테이션 정의 또는 기존에 정의된 애노테이션 사용
// - 클래스나 인터페이스에 적용
//=> .class 파일에 포함된 애노테이션을 확인하라!
//
@MyAnnotation // 클래스 선언에 붙일 수 있다.
public class Exam0110 {
@MyAnnotation // 필드에 붙일 수 있다.
static int a;
@MyAnnotation int b; // 필드 선언 바로 앞에 둘 수 있다.
@MyAnnotation // 메서드 선언에 붙일 수 있다.
void m1(
@MyAnnotation
int p1, // 파라미터(로컬변수)에 붙일 수 있다.
@MyAnnotation String p2
) {
@MyAnnotation int local; // 로컬변수 선언에 붙일 수 있다.
//@MyAnnotation System.out.println("okok"); // 그러나 다른 일반 문장에는 붙일 수 없다.
//@MyAnnotation // 다른 일반 문장에는 붙일 수 없다.
for (int i = 0; i < 100; i++) {
@MyAnnotation int a; // 로컬 변수 선언에 붙일 수 있다.
}
}
@MyAnnotation // static, non-static 상관없이 메서드 선언에 붙일 수 있다.
static void m2() {
}
}
// 애노테이션 정의
package com.eomcs.annotation.ex1;
public @interface MyAnnotation {
}
//한 줄 주석
//- 소스 코드의 설명을 붙일 때 사용
//- 컴파일 할 때 .class 파일에 포함되지 않음
/*
여러 줄 주석
- 소스 코드에 여러 줄의 설명을 붙일 때 사용
- 컴파일 할 때 .class 파일에 포함되지 않음
*/
/**
javadoc 주석
- javadoc.exe 를 통해 HTML API 문서를 생성할 때 사용됨.
- 컴파일 할 때 .class 파일에 포함되지 않음
*/
//애노테이션
//- 클래스 파일(.class)에 남길 수 있는 주석
//- 형식을 갖춘 주석이다.
//- 형식?
// @애노테이션이름(프로퍼티=값, 프로퍼티=값)
//- 활용
// 1) 소스 코드에서 주석을 읽어 다른 소스 파일을 생성할 때 사용
// 2) 컴파일할 때 주석을 추출하여 사용(컴파일러가 사용하는 내장 애노테이션)
// 2) 실행 중에 주석을 추출하여 사용
애노테이션 프로퍼티 사용
package com.eomcs.annotation.ex1;
@MyAnnotation2(value="okok")
public class Exam0120 {
@MyAnnotation2(value="okok")
int a;
@MyAnnotation2(value="okok")
void m() {}
}
// 애노테이션 프로퍼티
package com.eomcs.annotation.ex1;
public @interface MyAnnotation2 {
// 프로퍼티를 정의할 수 있다.
// => 인터페이스에서 메서드를 정의하는 것과 유사하다.
// => 메서드 이름은 프로퍼티(변수)명처럼 작성한다.
// 즉 일반적인 메서드는 보통 동사로 이름을 시작하지만,
// 애노테이션은 명사(명사구)로 이름을 짓는다.
// => 값을 꺼낼 때, 메서드 호출로 꺼낸다.
// => 애노케이션에서 값을 설정할 때는
// 다음과 같이 변수 형태를 사용한다.
// value="hello"
// 그래서 프로퍼티의 이름을 변수 형태로 짓는 것이다.
// 즉, getValue 가 아니라 value라고 한다.
String value(); // 애노테이션의 기본 프로퍼티이다.
}
com.eomcs.annotation.ex2
애노테이션 유지 정책 확인
package com.eomcs.annotation.ex2;
//애노테이션 유지 범위
//=> CLASS
// - .class 파일까지는 유지된다.
// - 그러나 runtime에는 메모리에 로딩되지 않는다.
// - 애노테이션을 정의할 때 유지 범위를 지정하지 않으면 기본이 CLASS 이다.
//=> SOURCE
// - 컴파일 할 때 제거된다.
// - .class 파일에 포함되지 않는다.
// - 보통 소스 파일에서 애노테이션 값을 꺼내 다른 파일을 자동 생성하는 도구를 만들 때 많이 사용한다.
//=> RUNTIME
// - .class 파일까지 유지되고, runtime에 메모리에 로딩된다.
// - 실행 중에 애노테이션을 참조해야 할 경우에 많이 사용한다.
//
public class Exam0110 {
public static void main(String[] args) {
// MyClass.class 파일을 편집기로 열어서 확인해보라!
// 클래스 정보 객체로부터 애노테이션 정보 추출
Class<?> clazz = MyClass.class;
// => 유지정책 : CLASS
MyAnnotation obj = clazz.getAnnotation(MyAnnotation.class);
if (obj == null) {
System.out.println("MyAnnotation을 추출할 수 없습니다!");
} else {
// 값을 꺼낼 때는 메서드 호출하듯이 꺼내면 된다.
System.out.println("MyAnnotation.value=" + obj.value());
}
// => 유지정책 : SOURCE
MyAnnotation2 obj2 = clazz.getAnnotation(MyAnnotation2.class);
if (obj2 == null) {
System.out.println("MyAnnotation2를 추출할 수 없습니다!");
} else {
System.out.println("MyAnnotation2.value=" + obj2.value());
}
// => 유지정책 : RUNTIME
MyAnnotation3 obj3 = clazz.getAnnotation(MyAnnotation3.class);
if (obj3 == null) {
System.out.println("MyAnnotation3를 추출할 수 없습니다!");
} else {
System.out.println("MyAnnotation3.value=" + obj3.value());
}
}
}
// 애노테이션 사용
// => @애노테이션이름(프로퍼티명=값, 프로퍼티명=값, ...)
//
package com.eomcs.annotation.ex2;
@MyAnnotation(value="값1") // 유지정책 => CLASS
@MyAnnotation2(value="값2") // 유지정책 => SOURCE
@MyAnnotation3(value="값3") // 유지정책 => RUNTIME
public class MyClass {
}
// 컴파일 한 후 .class 파일을 확인해 보라!
// 애노테이션 유지 정책
package com.eomcs.annotation.ex2;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 애노테이션의 유지 정책을 지정하지 않으면 기본이 CLASS이다.
// => 컴파일 할 때 .class 파일에 포함된다.
// => 단, 실행할 때 메모리에 로딩되지 않기 때문에 리플랙션 API로 추출할 수 없다.
@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation {
String value();
}
//애노테이션 유지 범위
//1) SOURCE : 소스 파일에만 남긴다. *.class 파일에 포함 안됨. 즉 컴파일할 때 제거된다.
//2) CLASS (기본) : .class 파일에 포함. 실행할 때 로딩 안됨.
//3) RUNTIME : .class 파일에 포함. 실행할 때도 메모리에 로딩됨. 실행 시에 추출할 수 있다.
// 애노테이션 유지 정책
package com.eomcs.annotation.ex2;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 애노테이션 유지 정책을 SOURCE라고 지정하면
// => 해당 애노테이션은 컴파일할 때 제거된다.
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation2 {
String value();
}
// 애노테이션 유지 정책
package com.eomcs.annotation.ex2;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 애노테이션 유지 정책을 RUNTIME라고 지정하면
// => 해당 애노테이션은 .class 파일에 포함된다.
// => 실행할 때 메모리에 로딩되기 때문에 리플랙션 API로 추출할 수 있다.
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation3 {
String value();
}
com.eomcs.annotation.ex3
애노테이션 프로퍼티 값 지정하기
package com.eomcs.annotation.ex3;
//@MyAnnotation // 필수 프로퍼티 값을 지정하지 않으면 컴파일 오류!
@MyAnnotation(value="값") // OK!
@MyAnnotation2 // 애노테이션의 프로퍼티 값을 지정하지 않으면 default 값이 사용된다.
//@MyAnnotation2(value="물론 이렇게 프로퍼티 값을 지정해도 된다.")
public class MyClass {
}
// 애노테이션 프로퍼티 - 필수 프로퍼티
package com.eomcs.annotation.ex3;
public @interface MyAnnotation {
String value();
// default 값을 지정하지 않으면 필수 프로퍼티가 된다.
// 즉 애노테이션을 사용할 때 반드시 값을 지정해야 한다.
}
// 애노테이션 프로퍼티 - 선택 프로퍼티
package com.eomcs.annotation.ex3;
public @interface MyAnnotation2 {
String value() default "홍길동";
// default 값이 있으면,
// 애노테이션을 사용할 때 값을 지정하지 않아도 된다.
}
com.eomcs.annotation.ex4
애노테이션 프로퍼티 값 지정하기 - 프로퍼티 이름 생략
package com.eomcs.annotation.ex4;
//@MyAnnotation // 오류! 기본 값이 설정되어 있지 않기 때문에 반드시 프로퍼터 값을 지정해야 한다.
//@MyAnnotation(value="홍길동") // OK!
@MyAnnotation("홍길동") // OK! 'value' 라는 이름을 가진 프로퍼티는 이름 생략 가능!
public class MyClass {
}
// 애노테이션 프로퍼티 - value 프로퍼티
package com.eomcs.annotation.ex4;
public @interface MyAnnotation {
String value(); // 필수 프로퍼티
}
package com.eomcs.annotation.ex4;
//@MyAnnotation2 // tel 프로퍼티는 필수이다. 반드시 값을 지정해야 한다.
//@MyAnnotation2(tel = "222-2222") // OK!
//@MyAnnotation2("222-2222") // 프로퍼티 명이 'value'가 아닌 경우에는 이름 생략 불가!
public class MyClass2 {
}
// 애노테이션 프로퍼티 - 일반 프로퍼티
package com.eomcs.annotation.ex4;
public @interface MyAnnotation2 {
String tel(); // 필수 프로퍼티
}
package com.eomcs.annotation.ex4;
//@MyAnnotation3(value = "홍길동", tel = "222-2222") // OK!
@MyAnnotation3(tel = "222-2222", value = "홍길동") // OK!
// => 프로퍼티 값을 설정할 때 순서는 상관없다.
//@MyAnnotation3("홍길동",tel="222-2222") // 오류!
// value 외 다른 프로퍼티 값도 지정할 경우,
// value 이름 생략 불가!
// value 값만 지정할 때 생략 가능!
public class MyClass3 {
}
// 애노테이션 프로퍼티 - 프로퍼티 생략
package com.eomcs.annotation.ex4;
public @interface MyAnnotation3 {
String value(); // 필수 프로퍼티
String tel(); // 필수 프로퍼티
}
com.eomcs.annotation.ex5
애노테이션 프로퍼티 값 추출
package com.eomcs.annotation.ex5;
public class Exam01 {
public static void main(String[] args) {
Class<?> clazz = MyClass.class;
MyAnnotation obj = clazz.getAnnotation(MyAnnotation.class);
System.out.println(obj.v1());
System.out.println(obj.v2());
System.out.println(obj.v3());
}
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex5;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String v1() default "가나다";
int v2() default 100;
float v3() default 3.14f;
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex5;
// 애노테이션의 모든 프로퍼티에 기본 값이 설정되어 있다면
// 다음과 같이 프로퍼티 설정을 생략해도 된다.
// 프로퍼티 값 설정을 생략하면,
// 애노테이션을 정의할 때 지정한 값이 기본으로 적용된다.
@MyAnnotation
public class MyClass {
}
애노테이션 프로퍼티 값 추출 - 배열 값 추출
package com.eomcs.annotation.ex5;
public class Exam02 {
public static void main(String[] args) {
Class<?> clazz = MyClass2.class;
MyAnnotation2 obj = clazz.getAnnotation(MyAnnotation2.class);
printValues(obj.v1());
System.out.println("----------------------");
printValues(obj.v2());
System.out.println("----------------------");
printValues(obj.v3());
}
static void printValues(String[] values) {
for (String value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(int[] values) {
for (int value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(float[] values) {
for (float value : values) {
System.out.print(value + ",");
}
System.out.println();
}
}
// 애노테이션 프로퍼티 타입 - 배열
package com.eomcs.annotation.ex5;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
// 배열 프로퍼티의 기본 값을 지정할 때 중괄호를 사용한다.
String[] v1() default {"가나다","라마바"};
int[] v2() default {100, 200, 300};
float[] v3() default {3.14f, 4.14f, 5.14f, 6.14f};
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex5;
@MyAnnotation2
public class MyClass2 {
}
애노테이션 프로퍼티 값 추출 - 배열 값 추출
package com.eomcs.annotation.ex5;
public class Exam03 {
public static void main(String[] args) {
Class<?> clazz = MyClass3.class;
MyAnnotation3 obj = clazz.getAnnotation(MyAnnotation3.class);
printValues(obj.v1());
System.out.println("----------------------");
printValues(obj.v2());
System.out.println("----------------------");
printValues(obj.v3());
}
static void printValues(String[] values) {
for (String value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(int[] values) {
for (int value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(float[] values) {
for (float value : values) {
System.out.print(value + ",");
}
System.out.println();
}
}
// 애노테이션 프로퍼티 타입 - 배열
package com.eomcs.annotation.ex5;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation3 {
// String[] v1() default {"가나다"};
// int[] v2() default {100};
// float[] v3() default {3.14f};
// 배열 값이 한 개일 경우 중괄호를 생략할 수 있다.
String[] v1() default "가나다";
int[] v2() default 100;
float[] v3() default 3.14f;
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex5;
@MyAnnotation3
public class MyClass3 {
}
애노테이션 프로퍼티 값 추출 - 배열 값 추출
// 애노테이션 프로퍼티 타입 - 배열 값 지정
package com.eomcs.annotation.ex5;
@MyAnnotation3(
// 배열 값을 지정할 때 중괄호를 사용한다.
v1 = {"홍길동", "임꺽정", "유관순"},
v2 = {1000, 2000, 3000, 4000, 5000},
v3 = {1.12f, 2.23f, 3, 34f})
public class MyClass4 {
}
package com.eomcs.annotation.ex5;
public class Exam04 {
public static void main(String[] args) {
Class<?> clazz = MyClass4.class;
MyAnnotation3 obj = clazz.getAnnotation(MyAnnotation3.class);
printValues(obj.v1());
System.out.println("----------------------");
printValues(obj.v2());
System.out.println("----------------------");
printValues(obj.v3());
}
static void printValues(String[] values) {
for (String value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(int[] values) {
for (int value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(float[] values) {
for (float value : values) {
System.out.print(value + ",");
}
System.out.println();
}
}
애노테이션 프로퍼티 값 추출 - 배열 값 추출
// 애노테이션 프로퍼티 타입 - 배열 값 지정
package com.eomcs.annotation.ex5;
@MyAnnotation3(
// v1={"임꺽정"},
// v2={1111},
// v3={1.11f}
// 배열 값이 한 개일 경우 중괄호를 생략할 수 있다.
v1="임꺽정",
v2=1111,
v3=1.11f
)
public class MyClass5 {
}
package com.eomcs.annotation.ex5;
public class Exam05 {
public static void main(String[] args) {
Class<?> clazz = MyClass5.class;
MyAnnotation3 obj = clazz.getAnnotation(MyAnnotation3.class);
printValues(obj.v1());
System.out.println("----------------------");
printValues(obj.v2());
System.out.println("----------------------");
printValues(obj.v3());
}
static void printValues(String[] values) {
for (String value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(int[] values) {
for (int value : values) {
System.out.print(value + ",");
}
System.out.println();
}
static void printValues(float[] values) {
for (float value : values) {
System.out.print(value + ",");
}
System.out.println();
}
}
애노테이션 적용 범위 - 클래스나 인터페이스
package com.eomcs.annotation.ex6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
// @Target을 사용하여 애노테이션을 붙일 수 있는 범위를 제어할 수 있다.
//@Target(value = {ElementType.TYPE}) // 클래스나 인터페이스 선언에만 붙일 수 있다.
//@Target(value = ElementType.TYPE) // 한 개의 값만 설정할 경우 중괄호 생략 가능!
@Target(ElementType.TYPE) // 프로퍼티 이름이 'value'일 경우 이름 생략 가능!
public @interface MyAnnotation {
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex6;
// @MyAnnotation은 타입(인터페이스와 클래스)에만 붙일 수 있다.
@MyAnnotation // OK!
public class MyClass {
// @MyAnnotation
int i; // 컴파일 오류!
// @MyAnnotation
public void m(/*@MyAnnotation*/ int p) {
/*@MyAnnotationn*/ int a;
}
}
애노테이션 적용 범위 - 필드
package com.eomcs.annotation.ex6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface MyAnnotation2 {
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex6;
// @MyAnnotation2은 필드에만 붙일 수 있다.
//@MyAnnotation2
public class MyClass2 {
@MyAnnotation2 int i;
@MyAnnotation2 static int i2;
// @MyAnnotation2
public void m(/*@MyAnnotation2*/ int p) {
/*@MyAnnotation2*/ int a;
}
}
애노테이션 적용 범위 - 메서드
package com.eomcs.annotation.ex6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface MyAnnotation3 {
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex6;
// @MyAnnotation3는 메서드에만 붙일 수 있다.
//@MyAnnotation3
public class MyClass3 {
/*@MyAnnotation3*/ int i;
/*@MyAnnotation3*/ static int i2;
@MyAnnotation3
public void m(/*@MyAnnotation3*/ int p) {
/*@MyAnnotation3*/ int a;
}
}
애노테이션 적용 범위 - 로컬 변수
package com.eomcs.annotation.ex6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.LOCAL_VARIABLE)
public @interface MyAnnotation4 {
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex6;
// @MyAnnotation4는 로컬 변수에만 붙일 수 있다.
//@MyAnnotation4
public class MyClass4 {
/*@MyAnnotation4*/ int i;
/*@MyAnnotation4*/ static int i2;
//@MyAnnotation4
public void m(/*@MyAnnotation4*/ int p) {
@MyAnnotation4 int a;
}
}
애노테이션 적용 범위 - 로컬 변수 + 파라미터 + 필드
package com.eomcs.annotation.ex6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.FIELD})
public @interface MyAnnotation5 {
}
// 애노테이션 프로퍼티 타입
package com.eomcs.annotation.ex6;
// @MyAnnotation5는 로컬 변수, 파라미터, 필드에만 붙일 수 있다.
//@MyAnnotation5
public class MyClass5 {
@MyAnnotation5 int i;
@MyAnnotation5 static int i2;
//@MyAnnotation5
public void m(@MyAnnotation5 int p) {
@MyAnnotation5 int a;
}
}
com.eomcs.annotation.ex7
애노테이션 중복 사용 - 기본은 한 번만 가능
package com.eomcs.annotation.ex7;
public @interface Company {
String value();
}
// 애노테이션 중복 사용
package com.eomcs.annotation.ex7;
@Company("비트캠프")
//@Company("비트캠프") // 중복 사용 불가!
public class MyClass {
@Company("비트캠프")
//@Company("비트캠프") // 중복 사용 불가!
public void m1(int p) {}
@Company("비트캠프")
//@Company("비트캠프") // 중복 사용 불가!
public void m2(int p) {}
}
애노테이션 중복 사용 - 여러 번 사용 가능
package com.eomcs.annotation.ex7;
import java.lang.annotation.Repeatable;
// 애노테이션을 중복해서 사용할 수 있게 하려면
// - @Repeatable 로 표시해 줘야 한다.
// - 이때 반복에 대한 정보를 따로 정의한 애노테이션을 지정해야 한다.
@Repeatable(value=Employees.class)
public @interface Employee {
String value();
}
애노테이션 중복 사용 - 중복해서 사용할 애노테이션을 지정한다.
package com.eomcs.annotation.ex7;
public @interface Employees {
Employee[] value();
}
// 애노테이션 중복 사용
package com.eomcs.annotation.ex7;
// @Employees 애노테이션에 @Employee 반복을 정의하였다.
// 그리고 @Employee 애노테이션에 반복할 수 있음을 선언하였다.
// 따라서 다음과 같이 중복 선언할 수 있다.
//
@Employee("홍길동")
@Employee("임꺽정")
public class MyClass2 {
@Employee("홍길동")
@Employee("임꺽정")
public void m1(int p) {}
@Employee("홍길동")
@Employee("임꺽정")
public void m2(int p) {}
}