자바 리플렉션(java reflection) 클래스 변수, 함수 접근 :: 개발/일상_Mr.lee

자바 리플렉션(java reflection) 클래스 변수, 함수 접근

Posted by Mr.mandu.
2017. 12. 14. 17:37 개발/java,spring

안녕하세요.

오랜만에 포스팅을 하는 기분이네요.


프로젝트를 진행하다 vo에 있는 변수들의 이름이 필요한 상황이 있었습니다.

처음에 감이 안잡혀 이리저리 검색하다가 알게된

자바 리플렉션(java reflection)!

사실 리플렉션 이라고 말은 들어밨지만 제가 궁금한점이 리플렉션인줄 알고

약간 민망했네요.


리플렉션에는 많은 내용들이 있지만 

제가 써먹었던 것만 일단 정리해 두겠습니다.


리플렉션

객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다. 

투영, 반사 라는 사전적인 의미를 지니고 있다.


리플렉션으로부터 얻을수있는 정보

 - ClassName

 - Class Modifiers

 - Package Info

 - Superclass

 - Implemented Interfaces

 - Constructors

 - MethodsFields

 - Annotations


제가 만든 테스트 객체 입니다.

package lee.domain;

import lombok.Data;

@Data
public class ReflectVo {
	private String str;
	private String str2;
	private int num;
	
	public ReflectVo() {
		
	}
	
	private void function_one() {
		System.out.println("function_one call");	
	}
	private void function_two(String str) {
		System.out.println("function_two call " + str);
	}
}

getter, setter는 lombok을 사용하고 있어 

@Data 어노테이션으로 처리하였습니다.


[개발/spring boot, gradle, mybatis Project] - #번외_[spring boot] gradle Lombok 설치 (setter, getter 간소화)





그리고 리플렉션을 실행하는 소스 입니다.

package lee.comm.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import lee.domain.ReflectVo;

public class ReflectTest {
	/**
	가져올수 있는 정보
	ClassName
	Class Modifiers (public, private, synchronized 등)
	Package Info
	Superclass
	Implemented Interfaces
	Constructors
	MethodsFields
	Annotations
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InstantiationException 
	*/
	
	//클래스 정보
	//필드 조작
	public void objectAccessTest() throws Exception {
		
		ReflectVo reflectVo = new ReflectVo(); //해당 클래스의 인스턴스 생성

		//Object obj=vo;
		Class c = Class.forName("lee.domain.ReflectVo");  // 클래스 얻기
		boolean isClassIncetance = c.isInstance(new ReflectVo());  // instanceOf 기능과 같음
		Class[] itfc = c.getInterfaces();  // 구현한 모든 인터페이스들 얻기 - 구현은 여러개 가능하므로 Class[]  배열
		Class sc = c.getSuperclass();  // 상속받은 슈퍼클래스 얻기 - 상속은 하나만 가능하므로 단일 변수
		Constructor csrList[] = c.getDeclaredConstructors();  // 모든 생성자 얻기
		
		Field[] allFd = c.getDeclaredFields();
		//c.getFields() 
		
		Method[] allMs = c.getDeclaredMethods();  // 모든 메소드들 얻기 - 상속받은것들 포함
		//c.getMethods();
		
		Method[] myMs = c.getDeclaredMethods();  // 모든 메소드들 얻기 - 상속받은것들은 불포함
		//Method m = c.getMethod("메소드명", "파라미터타입");  // 특정 메소드 얻기

		System.out.println("isClassIncetance= : " + isClassIncetance);
		
		Object array=null;
		String name = "";
		for (Field field : allFd){
	            field.setAccessible(true);
	            name = field.getName();
	            System.out.println("필드타입 : " + field.getType());
	            System.out.println("필드명 : " + field.getName());
		}
		
		for (Method mthd : allMs){
			mthd.setAccessible(true);
			System.out.println("메소드명 : " + mthd.getName());
			if(mthd.getName().equals("function_one")) {
				mthd.invoke(reflectVo, null);
			}else if(mthd.getName().equals("function_two")) {
				mthd.invoke(reflectVo, "두번째 메소드 파라미터 ");
			}
		}
	}

}


소스를 보시면 이해가실거라 생각되는데 약간의 설명을 드리겠습니다.


저는 멤버변수의 접근과 멤버함수의 접을을 시도하였습니다.

기본적으로 클래스에 접근하기 위해


Class c = Class.forName("lee.domain.ReflectVo"); 

를 선언해주었습니다.


그리고 멤버변수, 멤버함수에 접근하고자 

Field[] allFd = c.getDeclaredFields();

//c.getFields() 

Method[] allMs = c.getDeclaredMethods();

//c.getMethods();


이 부분이 있는데 getDeclaredMethods로 해주어야 private 에 접근이 가능합니다.

기본적인 getMethods로는 public에만 접근가능합니다.

실행시켜보면 금방 알수 있습니다.


그리고 함수를 실행시키기위해

파라미터를 지정하여 invoke함수를 사용하였습니다.

mthd.invoke(reflectVo, null);

mthd.invoke(reflectVo, "두번째 메소드 파라미터 ");


저는 제가 필요한 부분만 사용하였습니다.

더욱 많은 내용은 검색하시길 바랍니다.


실행결과

isClassIncetance= : true

필드타입 : class java.lang.String

필드명 : str

필드타입 : class java.lang.String

필드명 : str2

필드타입 : int

필드명 : num

메소드명 : equals

메소드명 : toString

메소드명 : hashCode

메소드명 : function_one

function_one ---

메소드명 : function_two

function_two =두번째 메소드

메소드명 : setNum

메소드명 : getNum

메소드명 : setStr2

메소드명 : setStr

메소드명 : getStr2

메소드명 : getStr

메소드명 : canEqual