리플렉션(Reflection)은 객체를 통해 클래스의 정보를 분석해내는 프로그램 기법입니다. (사전적 의미 : 거울 등에 비친, 반사)

클래스 파일의 위치나 이름만 있으면 해당 클래스의 정보를 얻어내고, 객체를 생성하는 것 또한 가능하게 해주는 유연한 

프로그래밍을 위한 기법입니다. 동적으로 객체를 생성하는 것 또한 가능해집니다.

현재 많이 사용되는 스프링 프레임워크에서도 리플렉션을 아주 많이 사용하고 있습니다.



Class 클래스

Class 클래스는 리플렉션의 기초가 되는 클래스입니다.

자바 프로그래밍을 하다보면 .class 라는 문구가 코드 내에 빈번하게 등장합니다.

전부터 볼때마다 이건 뭐지.. 싶었습니다. 인스턴스를 전달하는것도 아니고 .class 라니?

String 클래스로 한번 찍어봤습니다. 반환형이 Class 클래스네요. Class 클래스라니.. 얜 뭐하는 앨까요


간단하게 얘기하자면, Class 클래스는 자바에서 사용되는 클래스들에 대한 구조를 가지고 있는 Class라고 보시면 됩니다.

일단 간단한 클래스를 하나 보시겠습니다.

public class User {
    public String id;
    public String pwd;
    public String name;
    public Integer birthDate;
    
    public User(){}

    public User(String id, String pwd, String name, Integer birthDate) {
        this.id = id;
        this.pwd = pwd;
        this.name = name;
        this.birthDate = birthDate;
    }

    @Override
    public String toString() {
        return "id : " + id + ", pwd : " + pwd + ", name : " + name +", birthdate : " + birthDate;
    }
    
    // setter , getter 생략
}

User 클래스는 4개의 필드, 2개의 생성자, 9개의 메서드(getter/setter 포함)라는 속성을 가지고 있는 클래스로 정의됩니다.

여기서 한 단계 더 높은 개념으로 생각해보면, 클래스라는 것 자체도 필드, 생성자, 메서드 등의 속성을 가지고 있습니다.

즉, Class 클래스는 이러한 클래스의 구조 자체를 하나의 클래스로 표현해놓은 클래스입니다.

Class 클래스 내부의 메서드를 보시면 이해가 편하실 겁니다.

Class 클래스에 정의된 메서드들의 목록입니다. 이해가 가시나요??

반환형인 Field, Method, Package, Constructor 등은 모두 reflect 패키지에서 제공해주는 클래스들입니다.

이렇듯 리플렉션을 통해 클래스의 정보를 알아내기 위한 기점에는 Class 클래스가 있는 것입니다.


이제 위에서 작성한 User 클래스에 리플렉션을 통해 정보를 뽑아내보겠습니다.

먼저 User 클래스를 Class 객체로 뽑아내야 하는데요. 매우 간단합니다.

Class.forName("패키지 전체 경로") 또는 클래스이름.class

위의 형태로 호출하게 되면 해당 클래스의 정보를 담은 Class 클래스가 반환됩니다.


public static void main(String[] args) throws ClassNotFoundException{
    Class user = Class.forName("joont.reflect.User"); //  User.class 도 가능
    
    System.out.println("====Field List====");
    
    for(Field field : user.getFields()){
        System.out.println(field.getName());
    }
    
    System.out.println("\n====Constructor List====");
    
    for(Constructor constructor : user.getConstructors()){
        
        System.out.print("개수  " + constructor.getParameterCount() + " = ");
        
        for(Class parameter : constructor.getParameterTypes()){
            System.out.print(parameter.getName() + " / ");
        }
        
        System.out.println();
    }
    
    System.out.println("\n====Method List====");
    
    for(Method method : user.getMethods()){
        System.out.println(method.getName());
    }
}

.class로 Class 객체를 얻어낸 뒤 getFields, getConstructors, getMethods로 정보를 뽑아내보았습니다.


결과창입니다.

참으로 신기합니다 ㅎㅎ

필드, 생성자, 메서드 외에도 어노테이션, 패키지 등등 다양한 정보를 추출해 낼 수 있습니다.


그리고 위와 같이 전체적인 배열의 형태로 뽑아내는 것 외에 인자를 줘서 각각 하나씩 뽑아올 수도 있습니다.

public static void main(String[] args) throws Exception{
    Class user = Class.forName("joont.reflect.User"); //  User.class 도 가능
    
    System.out.println(user.getField("birthDate").getType());
    
    System.out.println(user.getMethod("toString").getReturnType());
    
    System.out.println(user.getConstructor(new Class[]{String.class,String.class,String.class,Integer.class}));
}



getDeclaredXXX()

Class 클래스의 메서드를 보시면 getFields(), getMethods() 등 외에 getDeclaredXXX() 라는 메서드도 있습니다.

이는 public 외의 접근 제어자를 가진 속성에 접근하기 위한 메서드입니다.

현재는 User 클래스의 모든 필드, 생성자, 메서드가 public이므로 문제없이 각 속성을 잘 뽑아왔지만,

실상 위의 메서드들은 접근제어자가 public인 속성만 뽑아오는 메서드입니다.

getDeclaredXXX()은 접근 제어자에 상관없이 클래스의 모든 속성을 가져올 수 있습니다.


감사합니다.

'JAVA,JSP' 카테고리의 다른 글

enum  (0) 2017.02.16
리플렉션(2), Class 생성, Method 실행  (0) 2016.08.07
리플렉션(1), Class 클래스  (4) 2016.07.29
예외처리(2)  (0) 2016.07.03
예외처리(1)  (0) 2016.06.30
java.lang.NoSuchMethodError  (1) 2016.06.28

댓글을 달아 주세요