Reflect를 공부해보자.
Java를 공부하다 깜짝 놀랐다. 클래스 이름이 Class이고 메서드 이름이 Method인 놈들이 있었다.
구글링을 통해 Reflect라는 놈들이란것을 알았고 친절한 예제를 제공하는 블로그를 발견하였다.
아래 예제는 http://mysnyc.tistory.com/42 블로그를 참조하여 만든것이다. 하나씩 코딩을 하면서 어떤기능들을 하는지 알아보도록 하자.
기본적인 프로젝트 구조는 다음과 같다.
두개의 java파일로 이루어져있고 테스트를 할때 패키지명과 파일명을 정확하게 맞춰야 출력이 잘 될것이다.
TestReflectMethod.java 파일이다.
특별한 것은 없고 TestReflectMain 클레스에서 사용할 메서드들을 정의해 놓았다. 특별한 설명은 생략하도록 하겠다.
package reflect; public class TestReflectMethod { public String field; public TestReflectMethod() {} public TestReflectMethod(String field){ this.field = field; } public String getField(){ System.out.println("call field : " + field); return field; } public void methodA(){ System.out.println("call method A"); } public void methodB(String str){ System.out.println("call method B : " + str); } public String methodC() { System.out.println("call method C"); return "method C"; } }
다음은
위의 메서드들을 Reflect를 이용하여 호출하는것을 해보겠다. 클레스를 만들어 가면서 설명하도록 할 것이다.
TestReflectMain.java
package reflect; import java.lang.reflect.InvocationTargetException; public class TestReflectMain { public static void main(String [] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, NoSuchFieldException, InvocationTargetException{ Class getClass1 = Class.forName("reflect.TestReflectMethod"); //여기서 다양한 방법으로 클레스를 호출한다. Class getClass2 = TestReflectMethod.class; //위는 패키지명.클래스로 클래스를 호출하고 Class getClass3 = new TestReflectMethod().getClass(); //클래스명을 직접적거나 클래스를 System.out.println("getClass1 : " + getClass1); // 이렇게 가져온 클레스 안에는 무엇들이 들어있는지 출력해보자 System.out.println("getClass2 : " + getClass2); System.out.println("getClass3 : " + getClass3); } }
보는거와 같이 모두 같은 클래스가 들어가있다. 이제 좀더 깊이 들어가서 요놈들을 어떻게 사용하는지 보자.
다음 소스를 보고 무슨 기능을 하는 녀석들인지 나의 얕은 지식으로는 이해가 되지 않아서 출력을 해보았다.
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class TestReflectMain { public static void main(String [] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException{ Class getClass1 = Class.forName("reflect.TestReflectMethod"); Class getClass2 = TestReflectMethod.class; Class getClass3 = new TestReflectMethod().getClass(); //생성자에 인자가 없는 경우 Object object1 = getClass1.newInstance(); //생성자에 인자가 있는 경우 Class[] constructorParamClass = new Class[] {String.class}; Object[] constructorParamObject = new Object[] {"Reflect Test!!!"}; Constructor constructor = getClass1.getConstructor(constructorParamClass); Object object2 = constructor.newInstance(constructorParamObject); System.out.println("object1 : " + object1); System.out.println("constructorParamClass : " + constructorParamClass); System.out.println("constructorParamObject : " + constructorParamObject); System.out.println("constructor : " + constructor); System.out.println("object2 : " + object2); } }
출력을 해보니 다음과 같이 나왔다. Class와 Object배열에는 java.lang.Class의 어떤 값이 있는 것을 확인 할 수 있다.
Class에 String클레스를 넣었더니 아래 Constructor에 TestReflectMethod가 있고 인자로 java.lang.String이 있다는 것을 볼 수 있다.
아마도 클레스를 넣으면 저렇게 나오는듯 싶다. 테스트를 더해보고 싶지만 시간관계상 넘어가도록 한다. 해보고 싶은 분들은
테스트를 한후 리플을 달아주시길..
마지막으로 object2에는 TestReflectMethod를 가리키고 있고 메모리 주소같은게 있다. 위에서 Object 객체를 만들면서 선언한 문자열을 가리키고 있는
메모리 주소같다.
다음코드를 보자
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; public class TestReflectMain { public static void main(String [] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException{ Class getClass1 = Class.forName("reflect.TestReflectMethod"); Class getClass2 = TestReflectMethod.class; Class getClass3 = new TestReflectMethod().getClass(); //생성자에 인자가 없는 경우 Object object1 = getClass1.newInstance(); //생성자에 인자가 있는 경우 Class[] constructorParamClass = new Class[] {String.class}; Object[] constructorParamObject = new Object[] {"Reflect Test!!!"}; Constructor constructor = getClass1.getConstructor(constructorParamClass); Object object2 = constructor.newInstance(constructorParamObject); Field field = getClass1.getField("field"); 다음값이 추가 되었다. 필드란 메서드를 호출해온다. Object fieldObject = field.get(object2); 위의 Reflect Test란 놈을 가리킬것 같다는 놈을 필드에 넣었다. System.out.println(field); //요놈은 필드를 가리키는 주소를 담고 있을테고 System.out.println(fieldObject); //이놈이 아마 출력을 하겠지?? 한번 테스트를 해보자. } }
예상이 맞았다. 필드를 이용한 값을 출력했다. 좀 어렵긴 하지만 이해못할 정도는 아니다.
재미있는건 위에서 import하는 녀석들이 모두 lang패키지에 있는 녀석들이다. 직접적으로 클래스를 명시해주는 놈이 아니라
Class Method Field라는 놈을 통해서 아무 클래스나 메서드들을 매핑시켜주는 녀석들인듯 싶다. 어렵지만 익숙해지면 유용하게 사용할 수 있을 꺼 같다.
잡담은 그만하고 이제 위에서 선언했던 메서드들을 어떻게 호출하는지 알아보자
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestReflectMain { public static void main(String [] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException, IllegalArgumentException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException{ Class getClass1 = Class.forName("reflect.TestReflectMethod"); Class getClass2 = TestReflectMethod.class; Class getClass3 = new TestReflectMethod().getClass(); //생성자에 인자가 없는 경우 Object object1 = getClass1.newInstance(); //생성자에 인자가 있는 경우 Class[] constructorParamClass = new Class[] {String.class}; Object[] constructorParamObject = new Object[] {"Reflect Test!!!"}; Constructor constructor = getClass1.getConstructor(constructorParamClass); Object object2 = constructor.newInstance(constructorParamObject); Field field = getClass1.getField("field"); Object fieldObject = field.get(object2); System.out.println(fieldObject); //메소드에 인자가 없는 경우 Method method1 = getClass1.getMethod("methodA"); 역시 위에 방법이랑 비슷한다. methodA를 객체로 만들고 method1.invoke(object1); 함수를 불러온다는 뜻이다. 인자로는 호출원의 객체 클래스를 뜻하는듯 하다.
//메소드에 인자가 있을 경우 Class[] methodParamClass = new Class[] {String.class}; Object[] methodParamObject = new Object[] {"1 parameter"}; Method method2 = getClass1.getMethod("methodB", methodParamClass); 메서드를 호출하고 메서드명, 파라미터타입??을 명시해준듯하다. method2.invoke(object1, methodParamObject); 호출원의 객체와, 인자를 넣어주었다. 인자가 1 parameter이다. //메소드에 리턴값이 있을 경우 Method method3 = getClass1.getMethod("methodC"); methodC를 호출했다. Object returnObject = method3.invoke(object1); 리턴값을 Object에 담았다. System.out.println("methodC return value : " + returnObject); 리턴값을 출력했다. 다음 콘솔창을 통해서 결과를 확인해보자. } }
출력화면이다.
예상과 같이 인자값 전달과 리턴값을 출력한것을 확인할 수 있었다.
조금생소한 녀석이었지만 재밌고 조금 어렵기도 했다. reflect라는 놈은 반사하다 비추다라는 뜻을 가지고 있다.
이름과 같이 내가 보여주는놈을 그대로 반사해서 돌려주는 재미있는 녀석이었다. ㅎㅎㅎ
'Programming > 과거포스팅' 카테고리의 다른 글
2012년 4월 3일 - (0) | 2012.04.03 |
---|---|
자동로그인 스크립트 ... (0) | 2012.03.30 |
Java API (0) | 2012.03.28 |
이클립스 인코딩 설정 (0) | 2012.03.18 |
JSP 파일 업로드(COS라이브러리) (1) | 2012.03.17 |