Post

리플렉션(Reflection)

리플렉션(Reflection)이란?

리플렉션은 구체적인 클래스 타입을 알지 못하더라도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API입니다

자바는 정적인 언어라 부족한 부분이 많은데 이 동적인 문제를 해결하기 위해서 리플렉션을 사용합니다.

정적 언어: 컴파일 시점에 타입을 결정 ex) Java, C, C++ 등.. 동적 언어: 런타임 시점에 타입을 결정 ex) Javascript, Python, Ruby 등..

리플렉션 사용법

1
2
3
4
5
6
7
8
9
public class Dog {
	public String name = "poppy";

	public Dog() {
	}
	public void run() {
		System.out.println(name + "run");
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class DogMain {
	public static void main(String[] args) throws Exception {
		Dog dog = new Dog();
		Class<Dog> dogClass = Dog.class;

		// 클래스 이름 불러오기
		System.out.println("클래스명 -> " + dogClass.getName());
		// 클래스명 -> reflection.Dog

		// 생성자 불러오기
		System.out.println("생성자 -> " + dogClass.getDeclaredConstructor());
		// 생성자 -> public reflection.Dog()

		// 메서드 불러오기
		System.out.println("메서드 -> " + dogClass.getDeclaredMethod("run"));
		// 메서드 -> public void reflection.Dog.run()
		
		// 변수 불러오기
		System.out.println("변수명 -> " + dogClass.getDeclaredField("name"));
		// 변수명 -> public java.lang.String reflection.Dog.name

		// 변수의 값 불러오기 및 변경하기
		Field field = dogClass.getDeclaredField("name");
        
		System.out.println("변수값 -> " + field.get(dog));
		// 변수값 -> poppy
        
		field.set(dog, "chulsu");
		System.out.println("변수값 변경 -> " + field.get(dog));
		// 변수값 변경 -> chulsu
	}
}

리플렉션 단점

컴파일러 최적화를 전혀 받지 못합니다. 이로 인해 성능 저하이슈가 발생합니다.

  • 동적으로 클래스를 생성하기 때문에 JVM 컴파일러가 최적화 할 수 있는 여지가 없습니다.

private 메서드/변수 접근 가능 문제가 있습니다.

  • field.setAccesible(true)를 설정하게 되면 private으로 설정해놓은 것도 직접 접근이 가능해지기 때문에 내부를 노출해서 추상화가 파괴됩니다.

코드가 간결하지 못합니다.

  • 장황한 코드로 인해 가독성이 저하된다.

스프링과의 연관성

스프링의 @Autowired는 리플렉션을 사용하여 생성자 주입합니다.

@Autowired 어노테이션이 생성자 위에 적혀 있으면, 스프링은 리플렉션을 사용해서 해당 생성자를 통해 클래스의 인스턴스를 생성하고, 필요한 의존성을 주입합니다.

스프링 컨테이너는 리플렉션을 사용해서 해당 필드의 타입에 맞는 빈(bean)을 찾고,그 빈을 해당 필드에 할당합니다.

이를 통해 개발자는 객체의 생성과 의존성 관리를 수동으로 하지 않아도 됩니다.

This post is licensed under CC BY 4.0 by the author.