Class klass = Class.forName("com.russolsen.reflect.Employee"); Method[] methods = klass.getMethods(); for(Method m : methods ) { System.out.println( "Found a method: " + m ); }getMethods 는 클래스가 가지고 있는 public 메소드 각각에 해당하는 Method 객체의 배열을 반환합니다.
Found a method: public java.lang.String com.russolsen.reflect.Employee.toString() Found a method: public int com.russolsen.reflect.Employee.getSalary() Found a method: public void com.russolsen.reflect.Employee.setSalary(int) Found a method: public native int java.lang.Object.hashCode() Found a method: public final native java.lang.Class java.lang.Object.getClass() Found a method: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException Found a method: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException Found a method: public final void java.lang.Object.wait() throws java.lang.InterruptedException Found a method: public boolean java.lang.Object.equals(java.lang.Object) Found a method: public java.lang.String java.lang.Object.toString() Found a method: public final native void java.lang.Object.notify() Found a method: public final native void java.lang.Object.notifyAll()getMethods는 클래스의 사용자(client) 입장이기 때문에, 배열에는 자신이 가지고 있는 모든 public 메소드 (Object 까지 달하는 모든 상속 계층의 상위 클래스들에 있는 public 메소드까지 포함하여)를 배열에 담아 줍니다.
Class klass = Class.forName("com.russolsen.reflect.Employee"); Class[] paramTypes = {Integer.TYPE }; Method setSalaryMethod = klass.getMethod("setSalary", paramTypes); System.out.println( "Found method: " + setSalaryMethod);리플렉션을 사용하여 메소드를 호출하는 것은 constuctor를 호출하는 것과 매우 유사합니다. 앞서 살펴봤던 Method 객체만 있으면 되고 메소드에 인자로 넘겨 줄 배열과 메소드를 호출할 객체가 필요합니다. 아래에 있는 코드는 우리 직원에게 월급을 올려주기 위해서 Employee 객체에 있는 setSalary 메소드를 호출합니다.
Class klass = Class.forName("com.russolsen.reflect.Employee"); Class[] paramTypes = {Integer.TYPE }; Method setSalaryMethod = klass.getMethod("setSalary", paramTypes); Object theObject = klass.newInstance(); Object[] parameters = { new Integer(90000) }; setSalaryMethod.invoke(theObject, parameters);그냥 theObject.setSalary(9000)를 호출하지 않고 왜 그렇게 귀찮게 했을까요? 위에 있는 코드를 자세히 살펴보시길 바랍니다. 코드의 첫 번째 줄을 빼면 위에 있는 프로그램은 완전히 일반적입니다. 어떤 클래스의 어떤 객체든 상관없이 setSalary 메소드를 호출할 것입니다. 약간만 수정하면 어떤 클래스의 어떤 객체든 거기에 있는 모든 메소드를 호출하는 코드로 사용할 수 있습니다.
Class klass = Class.forName("com.russolsen.reflect.Employee"); System.out.println( "Class name: " + klass.getName()); Field[] fields = klass.getFields(); for(Field f : fields ) { System.out.println( "Found field: " + f); }Employee 가 두 개의 public 필드를 가지고 있기 때문에 두 개의 멤버를 가진 배열을 얻게 됩니다.
Class name: com.russolsen.reflect.Employee Found field: public java.lang.String com.russolsen.reflect.Employee._firstName Found field: public java.lang.String com.russolsen.reflect.Employee._lastNamegetField메소드를 사용하여 특정 필드 하나만 가져올 수도 있습니다.
Field field = klass.getField("_firstName"); System.out.println("Found field: " + field);Field 객체를 가지고 get 메소드를 호출하면 필드가 가진 값을 가져올 수 있고 set을 사용하여 값을 설정할 수 있습니다.
Object theObject = new Employee("Tom", "Smith", 25); Class klass = Class.forName("com.russolsen.reflect.Employee"); Field field = klass.getField("_firstName"); Object oldValue = field.get(theObject); System.out.println( "Old first name is: " + oldValue); field.set( theObject, "Harry"); Object newValue = field.get(theObject); System.out.println( "New first name is: " + newValue);위에 있는 코드를 실행하고 _firstName 필드가 변하는 것을 주의 깊게 살펴보시기 바랍니다.
Old first name is: Tom New first name is: Harry규칙 깨기
ArrayList list = new ArrayList(); list.add("Larry"); list.add("Moe"); list.add("Curley"); System.out.println("The list is: " + list); Class klass = list.getClass(); Class[] paramTypes = { Integer.TYPE, Integer.TYPE }; Method m = klass.getDeclaredMethod("removeRange", paramTypes); Object[] arguments = { new Integer(0), new Integer(2) }; m.setAccessible(true); m.invoke(list, arguments); System.out.println("The new list is: " + list);private 메소드를 받은 뒤에 간단히 setAccessable 안전장치를 제거하고 호출하면 됩니다.
The list is: [Larry, Moe, Curley] The new list is: [Curley]removeRange 메소드는 리스트에서 주어진 범위의 아이템을 제거하는 것처럼 보입니다. 이것은 매우 강력한 마술입니다. java.util 에 있는 클래스에 접근하여 그 안에 있는 private 메소드를 호출할 수 있습니다. 이것을 사용하여 코드의 의도를 우회하여 private 메소드를 호출하는 취미를 즐기실 건가요? 아니죠! 그러나 저런 것들이 약간은 유용할 때가 있습니다.
이전 글 : Java 리플렉션에 대한 재고(reflection)(1)
다음 글 : 예제로 설명하는 쓰레드 제어하기(1)
최신 콘텐츠