반응형
강의 출처
과제 내용
우리는 최초로 API를 만들어 보았습니다. GET API를 만들기 위해 사용했던 어노테이션에 익숙하지 않다면 자바 어노테이션에 대해서 몇 가지 블로그 글을 찾아보세요! 다음 질문을 생각하며 공부해보면 좋습니다! 😊
[질문]
- 어노테이션을 사용하는 이유 (효과) 는 무엇일까?
- 나만의 어노테이션은 어떻게 만들 수 있을까?
답변
어노테이션의 역할
- 컴파일러에게 문법 에러를 체크하도록 정보 제공
- 프로그램을 빌드할 때 코드를 자동으로 생성할 수 있도록 정보 제공
- 런타임에 특정 기능을 실행하도록 정보 제공
반응형
(예시가 100% 맞는지 장담은 할 수 없음!)
컴파일러에게 문법 에러를 체크하도록 정보 제공
@Override
@Override 어노테이션은 상속 받은 메서드를 재정의할 때 사용하는 어노테이션이다. 이 어노테이션을 사용하면 부모 객체에 없는 메서드를 재정의했을 때 컴파일러 과정에서 에러를 발생시켜줍니다. (컴파일 에러는 가장 좋은 에러!)
Parent.class
public class Parent {
public void test1() {
System.out.println("Parent.test1");
}
public void test2() {
System.out.println("Parent.test2");
}
public void test3() {
System.out.println("Parent.test3");
}
}
Child.class
public class Child extends Parent{
public void test1() {
System.out.println("Child.test1");
}
public void test4() {
System.out.println("Child.test4");
}
}
목적은 Child가 Parent 클래스의 test1, test3 메서드를 재정의 하도록 하는 것이었는데 오타로 test3()을 test4()로 적고 실행해보면 당연히 아무런 에러가 발생하지 않고 프로그램이 정상적으로 종료된다.
public class OverrideMain {
public static void main(String[] args) {
Child child = new Child();
child.test1();
child.test4();
}
}
반응형
이런 경우를 방지하기 위해 재정의를 위한 메서드에 @Override 어노테이션을 붙여주면 된다.
public class Child extends Parent{
@Override
public void test1() {
System.out.println("Child.test1");
}
@Override
public void test4() {
System.out.println("Child.test4");
}
}
@Override 어노테이션을 추가 후 서버를 실행해보면 에러가 발생한다.
IDE에서도 직관적으로 바로 알려준다.
나만의 어노테이션은 어떻게 만들 수 있을까?
Java Class를 생성할 때 Annotation을 선택한다.
기본 형식
public @interface MyAnnotation {
}
MyAnnotation 코드 추가
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "MyAnnotation : default value";
}
- @Target : 생성할 어노테이션이 적용될 수 있는 위치 나열
- ElementType.TYPE : 클래스, 인터페이스, 열거 타입
- ElementType.ANNOTATION_TYPE : 어노테이션
- ElementType.FILED : 필드
- ElementType.CONSTRUCTOR : 생성자
- ElementType.METHOD : 메서드
- ElementType.LOCAL_VARIABLE : 로컬 변수
- ElementType.PACKAGE : 패키지
반응형
// Target 클래스 파일
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation interface
* can be applied to.
* @return an array of the kinds of elements an annotation interface
* can be applied to
*/
ElementType[] value();
}
// ElementType[] enum 클래스 파일
public enum ElementType {
/** Class, interface (including annotation interface), enum, or record
* declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation interface declaration (Formerly known as an annotation type.) */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE,
/**
* Record component
*
* @jls 8.10.3 Record Members
* @jls 9.7.4 Where Annotations May Appear
*
* @since 16
*/
RECORD_COMPONENT;
}
- @Retention : 어노테이션이 언제까지 살아 남아있을지를 정함
- RetentionPolicy.SOURCE : 소스 코드(.java)까지 남아 있음
- RetentionPolicy.CALSS : 클래스 파일(.class)까지 남아 있음 (= 바이트 코드)
- RetentionPolicy.RUNTIME : 런타임까지 남아 있음 (= 사실상 안죽음)
// Retention 클래스 파일
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
// RetentionPolicy enum 클래스 파일
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
반응형
어노테이션 값 꺼내기
MyAnnotationTest.class
public class MyAnnotationTest {
@MyAnnotation
public void testMethod1() {
System.out.println("MyAnnotationTest.testMethod1");
}
@MyAnnotation(value = "My new Annotation")
public void testMethod2() {
System.out.println("MyAnnotationTest.testMethod2");
}
}
MyAnnotationMain.class
public class MyAnnotationMain {
public static void main(String[] args) throws NoSuchMethodException {
// testMethod1 어노테이션 값 가져오기
Method testMethod1 = MyAnnotationTest.class.getMethod("testMethod1");
Annotation[] annotations = testMethod1.getDeclaredAnnotations(); // 메서드에 선언된 어노테이션 객체 얻어옴
for (Annotation annotation : annotations) {
if(annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("value : " + myAnnotation.value());
}
}
// testMethod2 어노테이션 값 가져오기
Method testMethod2 = MyAnnotationTest.class.getMethod("testMethod2");
annotations = testMethod2.getDeclaredAnnotations(); // 메서드에 선언된 어노테이션 객체 얻어옴
for (Annotation annotation : annotations) {
if(annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("value : " + myAnnotation.value());
}
}
}
}
Reference
반응형