반응형

리플렉션이란?

  • 리플렉션이란 객체를 통해 클래스의 정보를 분석하는 기법
  • 컴퓨터 프로그램에서 런타임 시점에 사용되는 자신의 구조와 행위를 관리(type introspection)하고 수정할 수 있는 프로세스를 의미한다.

 

자바 리플렉션 API (Class<T>)

  • 자바 리플렉션 API는 Class<T> 객체로 부터 시작된다. 이 객체는 클래스 로딩 후에 힙(Heap) 영역에 저장된다.
  • Class 타입의 인스턴스를 얻는 방법은 크게 3가지가 있다.
    • 타입을 가지고 class 타입의 인스턴스를 가지고 오는 방법
    Class<Book> bookClass = Book.class;
    • 생성된 인스턴스를 가지고 class 타입의 인스턴스를 가지고 오는 방법
    Book book = new Book();
    Class<? extends Book> aClass = book.getClass();
    • 클래스가 속한 패키지명을 모두 포함한 이름(FQCN, Fully Qualified Class Name)을 가지고 class 타입의 인스턴스를 가지고 오는 방법
    • 클래스패스에 해당 클래스가 없다면 ClassNotFoundException이 발생한다.
    Class<?> aClass1 = Class.forName("me.devhistory.Book");

 

Class 타입의 인스턴스로 클래스 정보를 얻을 수 있다.

Book.java

public class Book {
    private static StringB= "BOOK";
    private static final StringC= "BOOK";
    private String a = "a";
    public String d = "d";
    protected String e = "e";

    public Book() {
    }

    public Book(String a, String d, String e) {
        this.a = a;
        this.d = d;
        this.e = e;
    }

    private void f(){
        System.out.println("F");
    }

    public void g(){
        System.out.println("g");
    }

    public int h(){
        return 100;
    }

}

MyBook.java

public class MyBook extends Book implements MyInterface{
}

App.java

public class App {

    public static void main(String[] args) throws ClassNotFoundException {

        Class<Book> bookClass = Book.class;
        Book book = new Book();
        
        Arrays.stream(bookClass.getFields()).forEach(System.out::println);
        Arrays.stream(bookClass.getDeclaredFields()).forEach(System.out::println);
        Arrays.stream(bookClass.getMethods()).forEach(System.out::println);
        Arrays.stream(bookClass.getDeclaredConstructors()).forEach(System.out::println);
        System.out.println(MyBook.class.getSuperclass());
        Arrays.stream(MyBook.class.getInterfaces()).forEach(System.out::println);
        Arrays.stream(Book.class.getDeclaredFields()).forEach(f -> {
            int modifiers = f.getModifiers();
            System.out.println(f);
            System.out.println("\tPublic: "+Modifier.isPublic(modifiers));
            System.out.println("\tProtected: "+Modifier.isProtected(modifiers));
            System.out.println("\tPrivate: "+Modifier.isPrivate(modifiers));
            System.out.println("\tStatic: "+Modifier.isStatic(modifiers));
        });
    }
}

 

  • public 필드 정보 확인
Arrays.stream(bookClass.getFields()).forEach(System.out::println);
//public java.lang.String me.devhistory.Book.d

 

  • 모든 필드 정보 확인
  • getDeclaredFields() 메소드 인자로 필드 이름을 주어 특정 필드만 가져오는 것도 가능하다.
Arrays.stream(bookClass.getDeclaredFields()).forEach(System.out::println);
//private static java.lang.String me.devhistory.Book.B
//private static final java.lang.String me.devhistory.Book.C
//private java.lang.String me.devhistory.Book.a
//public java.lang.String me.devhistory.Book.d
//protected java.lang.String me.devhistory.Book.e

 

  • public 메소드 정보 확인
Arrays.stream(bookClass.getMethods()).forEach(System.out::println);
//public int me.devhistory.Book.h()
//public void me.devhistory.Book.g()
//public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//public final void java.lang.Object.wait() throws java.lang.InterruptedException
//public boolean java.lang.Object.equals(java.lang.Object)
//public java.lang.String java.lang.Object.toString()
//public native int java.lang.Object.hashCode()
//public final native java.lang.Class java.lang.Object.getClass()
//public final native void java.lang.Object.notify()
//public final native void java.lang.Object.notifyAll()

 

  • 생성자 정보 확인
Arrays.stream(bookClass.getDeclaredConstructors()).forEach(System.out::println);
//public me.devhistory.Book()
//public me.devhistory.Book(java.lang.String,java.lang.String,java.lang.String)

 

  • 해당 클래스가 상속하는 부모 클래스 정보 확인
System.out.println(MyBook.class.getSuperclass());
//class me.devhistory.Book

 

  • 해당 클래스가 구현하는 인터페이스 정보 확인
Arrays.stream(MyBook.class.getInterfaces()).forEach(System.out::println);
//interface me.devhistory.MyInterface

 

  • 필드의 접근 수준지시자, Static 여부 등 정보 확인
Arrays.stream(Book.class.getDeclaredFields()).forEach(f -> {
            int modifiers = f.getModifiers();
            System.out.println(f);
            System.out.println("\tPublic: "+Modifier.isPublic(modifiers));
            System.out.println("\tProtected: "+Modifier.isProtected(modifiers));
            System.out.println("\tPrivate: "+Modifier.isPrivate(modifiers));
            System.out.println("\tStatic: "+Modifier.isStatic(modifiers));
        });

//private static java.lang.String me.devhistory.Book.B
	//Public: false
	//Protected: false
	//Private: true
	//Static: true

//private static final java.lang.String me.devhistory.Book.C
	//Public: false
	//Protected: false
	//Private: true
	//Static: true

//private java.lang.String me.devhistory.Book.a
	//Public: false
	//Protected: false
	//Private: true
	//Static: false

//public java.lang.String me.devhistory.Book.d
	//Public: true
	//Protected: false
	//Private: false
	//Static: false

//protected java.lang.String me.devhistory.Book.e
	//Public: false
	//Protected: true
	//Private: false
	//Static: false

 

  • 이 밖에도 메소드의 파라미터 타입, 파라미터 갯수, 리턴 타입, 제네릭 타입 등 클래스와 관련된 많은 정보를 확인할 수 있다.

[참고자료]

더 자바, 코드를 조작하는 다양한 방법, 백기선

리플렉션

 

반응형

+ Recent posts