자바 Reflection Api

큰모래·2023년 4월 17일
0

Reflection

구체적인 클래스 타입을 몰라도 그 클래스의 메서드, 타입, 변수들에 접근 할 수 있도록 해주는 자바 API

좀 더 구체적으로 설명하자면, 자바 소스 코드가 실행 중인 상태라면 jvm의 메모리 상에 자바 코드 내부의 클래스, 메서드, 필드 등의 정보가 올라가게 된다. 이 때, 자바 리플렉션을 통해 해당 정보들을 컴파일 시점이 아닌, 런타임 시점에 동적으로 가져올 수 있다.


사용 예시

0. 예시에 사용할 Person 클래스 생성

	public class Person {
        
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(int age) {
            this.age = age;
        }

        private void doSomething() {
            System.out.println("Something is done!");
        }
    }

1. 클래스 정보 불러오기

  • 클래스 이름, 필드 정보, 메서드 정보를 불러올 수 있다.
    		public static void main(String[] args) {
    
            //클래스 불러오기
            Class<Person> personClass = Person.class;
    
            //클래스 이름 출력
            System.out.println(personClass.getName());
    
            //클래스 필드 정보 출력
            Field[] fields = personClass.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("field : " + field);
            }
    
            //클래스 메서드 정보 출력
            Method[] methods = personClass.getMethods();
            for (Method method : methods) {
                System.out.println("method : " + method);
            }
    
        }
  • 출력결과

    메서드를 보면 최상위 타입인 Object 메서드도 불러온다.

2. 객체 생성

    //생성자 만들어서 객체 생성
    Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
    Person person = constructor.newInstance("Son Seung Wan", 25);
    System.out.println("name : " + person.getName() + ", age : " + person.getAge());
  • getConstructor() 메서드를 통해 객체를 생성할 생성자 객체를 만들 수 있다.
  • 생성자 객체의 newInstance 메서드를 통해 객체 생성
  • 출력 결과

3. 메서드 호출하기

//메서드 호출하기
Method method = personClass.getDeclaredMethod("getName");
System.out.println("name : " + method.invoke(person));
  • getDeclaredMethod(”메서드명”) 을 통해 메서드 객체를 생성할 수 있다.
  • 최종적으로 invoke 를 통해 메서드 호출
  • 출력 결과

4. 필드 값 읽고 쓰기

//필드 값 읽고 쓰기
Field field = personClass.getDeclaredField("name");
String oldName = (String) field.get(person);

field.set(person, "Bigsand");
String newName = (String) field.get(person);

System.out.println("oldName : " + oldName + ", newName : " + newName);
  • getDeclaredField(필드명)을 통해 필드 객체를 불러올 수 있다.
  • 불러온 필드 객체를 통해 Person 객체의 필드 값을 읽을 수도 쓸 수도 있다.
  • 출력 결과

장단점

  • 장점
    • 런타임 시점에서 클래스의 인스턴스를 생성하고, 필드 및 메서드에 접근할 수 있는 유연성
  • 단점
    • 캡슐화 방해 (private으로 선언한 필드나 메서드에도 접근이 가능해짐)
    • 리플렉션을 통해 접근하면 성능이 느리다.
    • 런타임 시점에 인스턴스를 생성하므로 동작 흐름을 이해하기 어려워 진다.

스프링 컨테이너의 리플렉션

스프링 컨테이너에서 Bean 객체를 관리할 때 리플렉션 Api를 사용한다. 개발자가 컨트롤러, 서비스, 리포지토리 등에 @Controller 등의 어노테이션을 붙이면, 스프링 컨테이너의 Bean Factory는 런타임 시점에서 Bean 클래스를 동적으로 로딩하고 Bean 객체를 등록한다. 이렇게함으로서, Bean 객체 관리를 유연하게 할 수 있다.

profile
큰모래

0개의 댓글