IMCAT.DEV
로그인 가입
Java 중급 객체지향

Java 애너테이션과 리플렉션

Java 애너테이션과 리플렉션 — 중급

애너테이션과 리플렉션

1. 도입 (왜 배워야 하는가)

애너테이션(Annotation)과 리플렉션(Reflection)은 Java에서 강력한 기능을 제공하여 코드의 유연성을 높이고, 메타 프로그래밍을 가능하게 합니다. 실무에서는 이 두 가지를 활용하여 코드의 유지보수성을 높이고, 반복적인 작업을 줄이며, 프레임워크를 구축하는 데 도움을 줍니다.

예를 들어, Spring 프레임워크에서는 애너테이션을 통해 의존성 주입(Dependency Injection)을 간편하게 처리합니다. 만약 애너테이션과 리플렉션을 이해하지 못한다면, 복잡한 프레임워크를 제대로 활용하지 못하거나, 비효율적인 코드 작성으로 이어질 수 있습니다.

2. 핵심 개념 설명

애너테이션

애너테이션은 코드에 메타데이터를 추가하는 방법으로, 주석과 유사하지만 컴파일러나 JVM에서 처리할 수 있는 정보를 제공합니다. 예를 들어, @Override는 메서드가 부모 클래스의 메서드를 오버라이드함을 나타냅니다.

비유: 애너테이션은 도서관의 책에 붙은 태그와 같습니다. 태그는 책의 주제나 내용을 간단히 알려주며, 책을 찾는 데 도움을 줍니다.

리플렉션

리플렉션은 Java에서 클래스를 동적으로 탐색하고, 객체의 메타정보를 얻거나, 메서드를 호출할 수 있는 기능입니다. 이를 통해 런타임 시점에서 객체의 타입과 메서드 정보를 알 수 있습니다.

비유: 리플렉션은 상자 안에 무엇이 들어 있는지 보거나, 상자에 담긴 물건을 꺼내는 것과 같습니다. 상자를 열고 그 안에 무엇이 있는지 확인할 수 있습니다.

용어설명
애너테이션메타데이터를 제공하는 특별한 형태의 주석
리플렉션런타임 시점에서 객체의 정보를 탐색하고 조작하는 방법

3. 기본 코드 예제

// 애너테이션 정의
@interface MyAnnotation {
    String value();
}

// 애너테이션 사용
@MyAnnotation("Hello, Annotation!")
public class MyClass {
    public void myMethod() {
        System.out.println("My Method");
    }
}

// 리플렉션을 이용한 애너테이션 접근
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = MyClass.class; // MyClass 클래스 정보 얻기
        MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class); // 애너테이션 가져오기
        System.out.println(annotation.value()); // 애너테이션의 값 출력
        
        Method method = clazz.getMethod("myMethod"); // 메서드 정보 얻기
        method.invoke(clazz.getDeclaredConstructor().newInstance()); // 메서드 호출
    }
}

실행 결과

Hello, Annotation!
My Method

코드 한 줄씩 동작 설명

  1. @interface MyAnnotation - 애너테이션을 정의합니다.
  2. @MyAnnotation("Hello, Annotation!") - MyClass에 애너테이션을 적용합니다.
  3. Class<?> clazz = MyClass.class; - MyClass의 클래스를 가져옵니다.
  4. MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class); - 애너테이션 정보를 얻습니다.
  5. System.out.println(annotation.value()); - 애너테이션의 값을 출력합니다.
  6. Method method = clazz.getMethod("myMethod"); - myMethod 메서드 정보를 가져옵니다.
  7. method.invoke(clazz.getDeclaredConstructor().newInstance()); - myMethod를 호출합니다.
  8. 4. 실전 활용 예제

    1. 유효성 검사

    쇼핑몰에서 장바구니를 구현할 때, 상품의 가격이 유효한지 검사하는 애너테이션을 만들 수 있습니다.

    @interface Price {
        double min() default 0;
    }
    
    class Product {
        @Price(min = 0)
        private double price;
    
        public Product(double price) {
            this.price = price;
        }
    }

    2. 의존성 주입

    Spring 프레임워크에서 @Autowired 애너테이션을 사용해 의존성을 자동으로 주입합니다.

    class Service {
        // 의존성이 자동 주입됨
    }
    
    class Controller {
        @Autowired
        private Service service; // Service 객체가 자동으로 주입됨
    }

    5. 흔한 실수와 주의사항

    실수 1: 애너테이션을 잘못 정의하기

    // 잘못된 애너테이션 정의
    @interface MyAnnotation {
        String value(); // 기본값이 없음
    }
    • 올바른 코드: 기본값을 제공해야 합니다.
    • @interface MyAnnotation {
          String value() default "default value";
      }

      실수 2: 리플렉션 사용 시 예외 처리 누락

      // 예외 처리를 하지 않음
      Method method = clazz.getMethod("myMethod");
      method.invoke(clazz.newInstance()); // 예외 발생 가능
    • 올바른 코드: 예외 처리를 추가해야 합니다.
    • try {
          Method method = clazz.getMethod("myMethod");
          method.invoke(clazz.getDeclaredConstructor().newInstance());
      } catch (Exception e) {
          e.printStackTrace();
      }

      6. 정리

    • 애너테이션은 메타데이터를 제공하여 코드의 가독성과 유지보수성을 높입니다.
    • 리플렉션은 런타임 시점에서 클래스의 정보를 동적으로 탐색하고 조작할 수 있게 합니다.
    • 이 두 기능은 Java 프레임워크에서 광범위하게 사용됩니다.
    • 다음에 학습하면 좋은 주제로는 Spring 프레임워크의 의존성 주입, JPA에서의 애너테이션 활용이 있습니다.