[Java] - Object 클래스 (getClass), 그리고 Reflection API

janjanee·2021년 6월 11일
0

Java

목록 보기
7/19
post-thumbnail

getClass()

// Object.java

public final native Class<?> getClass();

Object 클래스편 마지막으로 getClass()를 살펴보자.
Object 클래스 코드를 살펴보면 리턴타입이 Class 이다.
Class 클래스가 무엇일까?

Class 클래스 는 클래스와 인터페이스(Class, Interface, Enum, Annotation...)의 모든 정보를 담고있는 클래스이다.
클래스 당 1개만 존재하며, 클래스 로더에 의해서 메모리에 올라갈 때 힙 영역에 자동으로 생성된다.

바로 코드로 이해해보자.

public class Book implements Readable {
    private String name;
    private int price;
    private int stock;
    public static final int OFF = 30;

    public Book(String name, int price) {
        this.name = name;
        this.price = price;
    }

    private boolean isSoldOut() {
        return this.stock < 0;
    }
    
    // getter, setter
    ...
}
public static void main(String[] args) throws Exception {

    Book book = new Book("SPRING BOOK", 10000);
    Class<? extends Book> bookClass = book.getClass();

}

간단하게 Book 클래스를 만들고, Object 클래스에서 상속받은 getClass() 를 호출했다.
위의 설명에서 Class 클래스는 클래스의 정보를 담고 있는 클래스라고 했다.

그럼 Class 클래스로 어떤 일을 할 수 있는걸까 생각해보자.

  • Book의 name, price 값을 확인할 수 있나?
  • Book의 isSoluOut() 같은 메소드가 private 제어자 임에도 불구하고 실행할 수 있을까?

모두 가능하다!

왜? Java Reflection API 기법을 사용하기 때문에 가능하다.

Reflection API

Reflection 이란?
구체적인 클래스 타입을 알지 못해도 그 클래스의 정보(메소드, 타입, 변수, ...)에
접근할 수 있게 해주는 자바 API 기법

Class<T>를 가지고 할 수 있는 것들은 다음과 같다.

  • 필드 가져오기
  • 메소드 가져오기
  • 상위 클래스 가져오기
  • 인터페이스 가져오기
  • 애노테이션 가져오기
  • 생성자 가져오기
  • ...

예제를 통해 가볍게 Reflection을 사용해보자.

1. Class<T> 접근

// 1.  클래스 리터럴(*.class)로 얻기
Class<Book> bookClass = Book.class;
// 2. 생성된 객체로 얻기
Book book = new Book("SPRING BOOK", 10000);
Class<? extends Book> bookClass2 = book.getClass();
// 3. 클래스 이름(FQCN)으로 얻기
Class<?> bookClass3 = Class.forName("com.jihan.javastudycode.lang.Book");

2. 필드 목록 가져오기

Arrays.stream(bookClass.getDeclaredFields()).forEach(f -> {
    try {
        f.setAccessible(true);  //  true로 지정해야 private 접근가능
        System.out.printf("%s %s \n", f, f.get(book));
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
});
결과
private java.lang.String com.jihan.javastudycode.lang.Book.name SPRING BOOK 
private int com.jihan.javastudycode.lang.Book.price 10000 
private int com.jihan.javastudycode.lang.Book.stock 0 
public static final int com.jihan.javastudycode.lang.Book.OFF 30 

getFields()를 할 경우 private 접근 제어자는 보이지 않음.

3. 메소드 목록 가져오기

Arrays.stream(bookClass.getDeclaredMethods()).forEach(System.out::println);
결과
public java.lang.String com.jihan.javastudycode.lang.Book.getName()
public java.lang.String com.jihan.javastudycode.lang.Book.toString()
public void com.jihan.javastudycode.lang.Book.setName(java.lang.String)
public int com.jihan.javastudycode.lang.Book.getPrice()
public void com.jihan.javastudycode.lang.Book.setPrice(int)
public int com.jihan.javastudycode.lang.Book.getStock()
public void com.jihan.javastudycode.lang.Book.setStock(int)
private boolean com.jihan.javastudycode.lang.Book.isSoldOut()

getMethods()를 할 경우 private 접근 제어자는 보이지 않음.
getMethods()를 할 경우 상속받은 메소드도 보여짐.

4. 상위 클래스 가져오기

System.out.println(bookClass.getSuperclass());
결과
class java.lang.Object

5. 인터페이스 목록 가져오기

Arrays.stream(bookClass.getInterfaces()).forEach(System.out::println);
결과
interface com.jihan.javastudycode.lang.Readable

6. 생성자로 인스턴스 만들기

Constructor<Book> constructor = bookClass.getConstructor(String.class, int.class);
Book theLordOfTheRings = constructor.newInstance("반지의 제왕", 20000);

정리

그런데 특별한 경우가 아닌 이상 애플리케이션 개발 시 Reflection을 자주 사용하는 일은 없을 것이다.
그렇다면 Reflection 기술은 주로 어디서 활용되고 있는걸까?

  • Spring
    • 의존성 주입
    • MVC 뷰에서 넘어온 데이터 객체 바인딩
  • Hibernate
    • @Entity Setter가 없으면 필드에 값을 바로 설정
  • JUnit, IntelliJ

다양한 프레임워크나 라이브러리 개발환경에서 많이 사용되는 기술이다.

또한 사용시 주의할 점이 몇 가지 있는데 강력한 기능인만큼 주의해서 쓰지 않으면 아래와 같이 문제가 발생할 수 있다.

  • 지나친 사용으로 인한 성능이슈. 반드시 필요한 경우에만 사용
  • 컴파일 타임에 확인되지 않고 런타임 시에만 발견할 수 있는 문제 발생 가능성
  • 접근지시자 무시

Refernces

https://docs.oracle.com/javase/tutorial/reflect/
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Class.html
https://www.geeksforgeeks.org/reflection-in-java/
https://woowacourse.github.io/javable/post/2020-07-16-reflection-api/
https://www.inflearn.com/course/the-java-code-manipulation

profile
얍얍 개발 펀치

0개의 댓글