[Java] 31. Reflection 기능을 사용하는 방법 - Variable편


Study/Java  2020. 6. 8. 14:49

안녕하세요. 명월입니다.

 

이 글은 Java에서의 Reflection 기능을 사용하는 방법 - 변수(Variable)편에 대한 글입니다.

 

이전 글에서 Java의 Reflection 기능을 Class와 Method를 나누어서 설명했습니다.

링크 - [Java] 29. Reflection 기능을 사용하는 방법 - Class편

링크 - [Java] 30. Reflection 기능을 사용하는 방법 - Method편

 

Class에서 Method에서는 String으로 클래스를 찾거나 메소드를 찾아서 할당하거나 호출하는 게 주요 Reflection 기능이었습니다.

이 Variable이라고 크게 다르지 않습니다.

 

그러나 이 맴버 변수는 보통 Java에서는 private의 접근자로 캡슐화를 만듭니다.

링크 - [Java] 14. 객체 지향(OOP) 프로그래밍의 4대 원칙(캡슐화, 추상화, 상속, 다형성)

 

보통 내부 클래스에서는 Reflection을 이용해서 변수를 참조하지 않습니다. 굳이 필요성이 없습니다. 내부 클래스인데...

외부에서 클래스를 찾거나 메소드를 찾아서 사용하는데 캡슐화로 멤버 변수는 private 처리가 되어있습니다.

그럼 어떨 때 사용할까요?

import java.lang.reflect.Field;
class Node {
  // private 타입입니다.
  private int data = 0;
  // 멤버 변수 설정
  public void setData(int data) {
    this.data = data;
  }
  // 멤버 변수 리턴
  public int getData() {
    return this.data;
  }
}
public class Example {
  // 실행 함수
  public static void main(String... args) {
    try {
      // 인스턴스 생성
      Node node = new Node();
      // Reflection으로 data 변수를 취득한다.
      Field field = Node.class.getDeclaredField("data");
      // setAccessible는 private, protected도 접근 가능하게 한다.
      field.setAccessible(true);
      // data 필드에 100를 넣는다.
      field.set(node, 100);
      // 결과는 100이 나온다.
      System.out.println(node.getData());
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }
}

위 예제를 보시면 Node 인스턴스를 생성하고 getDeclaredField로 데이터를 취득합니다.

setAccessible의 함수는 private일 경우 접근이 가능하게 설정하는 함수입니다.

 

사실, main에서 Node 인스턴스의 맴버 변수가 private 타입이여서 접근이 불가능합니다.

그러나 위 예제에서는 private 타입으로 된 data 변수를 취득했습니다. 그리고 데이터를 입력하기까지 했습니다.

즉, Reflection를 이용하면 Unit 테스트 프로그램을 작성할 때, 작성되어 있는 함수의 결과 값만 확인하는 것이 아니라 중간 중간 클래스의 맴버 변수 값을 확인할 수 있습니다.

import static org.junit.Assert.*;
import java.lang.reflect.Field;
import org.junit.Test;
class Node {
  // private 타입입니다.
  private int data = 0;
  // 멤버 변수 설정
  public void setData(int data) {
    this.data = data;
  }
  // 멤버 변수 리턴
  public int getData() {
    return this.data;
  }
}
public class TestCase {
  @Test
  public void test() {
    try {
      // 인스턴스 생성
      Node node = new Node();
      // data 필드에 100를 넣는다.
      node.setData(100);
      // Reflection으로 data 변수를 취득한다.
      Field field = Node.class.getDeclaredField("data");
      // setAccessible는 private, protected도 접근 가능하게 한다.
      field.setAccessible(true);
      // 테스트 검사
      assertEquals(field.get(node), 100);
    } catch (AssertionError e) {
      throw e;
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }
}

Method에도 있었지만 변수에도 클래스의 변수 리스트를 취득해오는 함수가 있습니다.

Method에서는 getDeclaredMethods가 현재 클래스, getMethods는 상위 클래스의 함수까지 나오는 것이었습니다.

변수는 약간 다릅니다. getDeclaredFields와 getFields의 차이는 getDeclaredFields는 private 포함 변수, getFields는 public만 있는 변수입니다.

캡슐화에서 변수를 public 할일이 없으니깐 아마 getDeclaredFields만 사용하게 됩니다.

사용할 때도 getDeclaredField와 getField가 있습니다만, 맴버 변수는 private로 되어 있으니 getDeclaredField만 사용하게 됩니다.

 

여기까지 Java에서의 Reflection 기능을 사용하는 방법 - 변수(Variable)에 대한 글이었습니다.

 

궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.