JAVA 일반 Java Reflection 정의

2015.09.05 21:47

졸리운_곰 조회 수:240

 

 

Java Reflection 정의

 

리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다. 투영, 반사 라는 사전적인 의미를 지니고 있다.

 

스프링을 공부하다가 보면 BeanFactory 라는 Spring Container 개념을 학습하게 된다.

이 BeanFactory는 어플리케이션이 실행한 후 객체가 호출 될 당시 객체의 인스턴스를 생성하게 되는데 
그 때 필요한 기술이 Reflection이다.
자바는 스크립트 언어가 아닌 컴파일 언어이다. 물론 .java -> .class -> 실행이라는 2단계의 메커니즘을 가지고 있지만 컴파일 언어로 분리하는 게 옳다. 원래 자바에서는 동적으로 객체를 생성하는 기술이 없었다. 그리고 동적으로 인스턴스를 생성하는 Reflection으로 그 역활을 대신하게 된다.
 
리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다. 투영, 반사 라는 사전적인 의미를 지니고 있다
 
가정을 해 보자. 만약 객체의 메모리만을 알고 있고, 그리고 객체의 형에 대해서는 모른다고 생각하보자, 

 

리플렉션으로 형은 알고 있지만 형변환을 할 수 없는 상태에서 객체의 메서드를 호출할 수 있다.

 

 

 

Class c = Data.class;
//Class c = Class.forName("클래스이름");
 

Method[] m = c.getMethods();                     

Field[] f = c.getFields();
Constructor[] cs = c.getConstructors();
Class[] inter = c.getInterfaces();
Class superClass = c.getSuperclass();
 

 

 

 

Java Reflection 의 사용

 

 

reflection 은 자바의 특징이다. 실행중인 자바프로그램 내부를 검사하고 내부의 속성을 수정할 수 있도록 한다. 예를 들어, 어떤 자바클래스가 가진 모든 멤버의 이름을 얻거나 보여줄 수 있다.
자바에서 클래스가 그 자신을 조사하고 수정하는 것이  많다고 할수는 없으나 다른 언어에서는 볼수 없는 특징이다.

reflection 이 구체적인 쓰임중에 하나가 빌더툴을 이용해서 소프트웨어 콤포넌트를 만드는 곳에서 이다. 툴은 reflection 을 사용해서 동적으로 로딩되는 자바 콤포넌트(클래스)의 속성을 얻을 수 있다.

 

예제

import java.lang.reflect.Method;

 

public class DumpMethods {

    public static void main(String args[]) {

        try {

            Class c = Class.forName(args[0]);

            Method m[] = c.getDeclaredMethods();

            for (int i = 0; i < m.length; i++)

                System.out.println(m[i].toString());

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

 

명령

java DumpMethods java.util.Stack

 

실행 결과

  public java.lang.Object java.util.Stack.push(
    java.lang.Object)
   public synchronized 
     java.lang.Object java.util.Stack.pop()
   public synchronized
      java.lang.Object java.util.Stack.peek()
   public boolean java.util.Stack.empty()
   public synchronized 
     int java.util.Stack.search(java.lang.Object)
 
이 프로그램은 java.util.Stack 의 속성과 반환값에 따라 메소드리스트를 출력한다.
이 프로그램은 Class.forName 을 통해서 클래스를 로딩하고 getDeclaredMethods 을 통해서 클래스에서 정의한 메소드리스트를 얻는다. java.lang.reflect.Method  는 단일 메쏘드를 나타내는 클래스이다.

 

Reflection 을 사용한 Set up
Method 와 같은 reflection class 는 java.lang.reflect 에 있다. 이 클래스를 사용하기 위해서는 세가지 스텝을 밟아야 한다.
첫번째는 수정하기를 원하는 클래스의 java.lang.Class 객체를 얻어야 한다. java.lang.Class 는 클래스를 표현하고, 실행중인 자바 프로그램과 인터페이스한다.

 

자바기본형에 대한 클래스 정보를 얻는 방법.
방법 1 : 
   Class c = Class.forName("java.lang.String");

 

방법 2 : 
   Class c = int.class;

 

방법 3 : 기본형의 경우 (Integer 와 같은) Wrapper 에 기정의된 TYPE을 사용한다. 
  Class c = Integer.TYPE;

 

두번째 스텝은 getDeclaredMethods와 같은 메소드를 Call 해서, 클래스에 정의된 모든 메소드의 리스트를 얻는다.

세번째 스텝은 정보 수정을 위해 Reflection API 를 이용한다.

   Class c = Class.forName("java.lang.String");
   Method m[] = c.getDeclaredMethods();
   System.out.println(m[0].toString());

String 에 선언된 첫번째 메소트를 보여준다.


 

Simulating the instanceof Operator
클래스 정보가 있으면, 다음 스텝은 클래스 객체에 대해서 기본적인 질의다. Class.isInstance 메쏘드는 instanceof 를 통해서 구현될 수 있다.

 

class A {}

 

public class instance1 {

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("A");

 

            boolean b1 = cls.isInstance(new Integer(37));

            System.out.println(b1);

 

            boolean b2 = cls.isInstance(new A());

            System.out.println(b2);

 

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

 
A의 클래스객체가 만들어진다. 그리고 class instance objects 가 A 의 인스턴스인지 체크한다. 
Integer(37) 은 아니지만, new A() 는 True 이다.


클래스 메쏘드 찾기
reflection 의 가장 기초적인 쓰임은 클래스에서 정의한 메소드가 무엇인지 찾아내는 것이다. 이를 위해서 다음 코드가 사용될 수 있다.

import java.lang.reflect.*;

 

public class method1 {

    private int f1(Object p, int x) throws NullPointerException {

        if (p == null)

            throw new NullPointerException();

        return x;

    }

 

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("method1");

 

            Method methlist[] = cls.getDeclaredMethods();

            for (int i = 0; i < methlist.length; i++) {

                Method m = methlist[i];

                System.out.println("name  = " + m.getName());

                System.out.println("decl class = " + m.getDeclaringClass());

                Class pvec[] = m.getParameterTypes();

 

                for (int j = 0; j < pvec.length; j++)

                    System.out.println(" param #" + j + " " + pvec[j]);

 

                Class evec[] = m.getExceptionTypes();

 

                for (int j = 0; j < evec.length; j++)

                    System.out.println("exc #" + j + " " + evec[j]);

 

                System.out.println("return type = " + m.getReturnType());

                System.out.println("-----");

            }

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

 

getDeclaredMethods 을 통해서 메쏘드 리스트를 조회한다. getDeclaredMethods 대신에 getMethods 를 사용하면 상속된 메쏘드에 대한 정보를 얻을 수 있다.

실행결과
   name = f1
   decl class = class method1
   param #0 class java.lang.Object
   param #1 int
   exc #0 class java.lang.NullPointerException
   return type = int
   -----
   name = main
   decl class = class method1
   param #0 class [Ljava.lang.String;
   return type = void
   -----
 
Constructors 에 대한 정보얻기

 

import java.lang.reflect.*;

 

public class constructor1 {

    public constructor1() {

    }

 

    protected constructor1(int i, double d) {

    }

 

    public static void main(String args[])

      {

         try {

           Class cls = Class.forName("constructor1");

        

           Constructor ctorlist[] = cls.getDeclaredConstructors();

           for (int i = 0; i < ctorlist.length; i++) {

               Constructor ct = ctorlist[i];

               System.out.println("name = " + ct.getName());

               System.out.println("decl class = " + ct.getDeclaringClass());

               Class pvec[] = ct.getParameterTypes();

               

               for (int j = 0; j < pvec.length; j++)

                  System.out.println("param #" + j + " " + pvec[j]);

               

               Class evec[] = ct.getExceptionTypes();

               

               for (int j = 0; j < evec.length; j++)

                  System.out.println("exc #" + j + " " + evec[j]);

               

               System.out.println("-----");

            }

          }

          catch (Throwable e) {

             System.err.println(e);

          }

      }

}

이 프로그램에서는 리턴타입정보가 없는데... 생성자는 리턴타입을 갖지 않기 때문이다.
실행결과
   name = constructor1
   decl class = class constructor1
   -----
   name = constructor1
   decl class = class constructor1
   param #0 int
   param #1 double
   -----
 
Class Fields 찾기

   import java.lang.reflect.*;

 

public class field1 {

    private double d;

    public static final int i = 37;

    String s = "testing";

 

    public static void main(String args[])

      {

         try {

             Class cls = Class.forName("field1");

             Field fieldlist[] = cls.getDeclaredFields();

             for (int i = 0; i < fieldlist.length; i++) {

                 Field fld = fieldlist[i];

                 System.out.println("name = " + fld.getName());

                 System.out.println("decl class = " + fld.getDeclaringClass());

                 System.out.println("type = " + fld.getType());

                 int mod = fld.getModifiers();

                 System.out.println("modifiers = " + Modifier.toString(mod));

                 System.out.println("-----");

            }

          }

          catch (Throwable e) {

             System.err.println(e);

          }

       }

}

이전예제와 비슷하다. 새로운 특징은 modifier 의 사용이다.
modifier는 'private int' 와 같은 필트멤버를 표현하기위한 reflection class 이다.
modifier 는 숫자로 표현된다. Modifier.toString 은 'final' 앞의 'static' 과 같은 선언순서의 문자열표현을 리턴한다.

실행결과 :
  name = d
   decl class = class field1
   type = double
   modifiers = private
   -----
   name = i
   decl class = class field1
   type = int
   modifiers = public static final
   -----
   name = s
   decl class = class field1
   type = class java.lang.String
   modifiers =
   ----- 
 
이름으로 메쏘드 실행하기.
  import java.lang.reflect.*;

 

public class method2 {

    public int add(int a, int b) {

        return a + b;

    }

 

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("method2");

            Class partypes[] = new Class[2];

            partypes[0] = Integer.TYPE;

            partypes[1] = Integer.TYPE;

            Method meth = cls.getMethod("add", partypes);

            method2 methobj = new method2();

            Object arglist[] = new Object[2];

            arglist[0] = new Integer(37);

            arglist[1] = new Integer(47);

            Object retobj = meth.invoke(methobj, arglist);

            Integer retval = (Integer) retobj;

            System.out.println(retval.intValue());

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

프로그램이 add 라는 메쏘드를 실행시키는데 실행시까지 알지 못한다고 가정해보자. 메쏘드 이름은 실행시간에 알수있다. 
getMethod 는 클래스에서 두개의 숫자 파라미터와 해당 이름을 가진 메쏘드를 찾아낸다.


새로운 객체 만들기

 import java.lang.reflect.*;

 

public class constructor2 {

    public constructor2() {

    }

 

    public constructor2(int a, int b) {

        System.out.println("a = " + a + " b = " + b);

    }

 

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("constructor2");

            Class partypes[] = new Class[2];

            partypes[0] = Integer.TYPE;

            partypes[1] = Integer.TYPE;

            Constructor ct = cls.getConstructor(partypes);

            Object arglist[] = new Object[2];

            arglist[0] = new Integer(37);

            arglist[1] = new Integer(47);

            Object retobj = ct.newInstance(arglist);

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}


필드값 바꾸기

  import java.lang.reflect.*;

 

public class field2 {

    public double d;

 

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("field2");

            Field fld = cls.getField("d");

            field2 f2obj = new field2();

            System.out.println("d = " + f2obj.d);

            fld.setDouble(f2obj, 12.34);

            System.out.println("d = " + f2obj.d);

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

 
배열의 사용

import java.lang.reflect.*;

 

public class array1 {

    public static void main(String args[]) {

        try {

            Class cls = Class.forName("java.lang.String");

            Object arr = Array.newInstance(cls, 10);

            Array.set(arr, 5, "this is a test");

            String s = (String) Array.get(arr, 5);

            System.out.println(s);

        } catch (Throwable e) {

            System.err.println(e);

        }

    }

}

 

 import java.lang.reflect.*;

 

public class array2 {

    public static void main(String args[]) {

        int dims[] = new int[] { 5, 10, 15 };

        Object arr = Array.newInstance(Integer.TYPE, dims);

 

        Object arrobj = Array.get(arr, 3);

        Class cls = arrobj.getClass().getComponentType();

        System.out.println(cls);

        arrobj = Array.get(arrobj, 5);

        Array.setInt(arrobj, 10, 37);

 

        int arrcast[][][] = (int[][][]) arr;

        System.out.println(arrcast[3][5][10]);

    }

}

 

[출처] http://gyrfalcon.tistory.com/entry/Java-Reflection

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
153 SWT and multithreading 졸리운_곰 2015.11.07 56
152 Eclipse RCP multithreading 졸리운_곰 2015.11.07 122
151 Eclipse RCP - Prevent UI freezing while running long operation 졸리운_곰 2015.11.07 87
150 Eclipse RCP Tutorial: How to Add a Progress Bar file 졸리운_곰 2015.11.07 97
149 Eclipse RCP 에서 configuration 설정 파일 사용하지 않기 secret 졸리운_곰 2015.11.07 0
148 Gson User Guide 졸리운_곰 2015.10.26 302
147 Java Google Json (Gson) Type Adapter 졸리운_곰 2015.10.26 125
146 TypeAdapter (Gson 2.3.1 API) - Google Gson 졸리운_곰 2015.10.26 108
145 Gson TypeAdapter Example file 졸리운_곰 2015.10.26 81
144 Deserializing a Map<String, Object> field with Gson 졸리운_곰 2015.10.23 46
143 How to de-serialize a Map<String, Object> with GSON 졸리운_곰 2015.10.23 566
142 Gson 이란? 졸리운_곰 2015.10.21 1712
141 GSON - Java 객체(object)를 JSON 표현식으로 변환하는 API 졸리운_곰 2015.10.21 295
140 GSON Serialiser Example [Java class의 JSON 변환] file 졸리운_곰 2015.10.21 193
139 Add a Custom Menu Action to an Eclipse RCP Application file 졸리운_곰 2015.10.16 1096
138 Java - Serialization file 졸리운_곰 2015.10.14 107
137 Save and restore view state via reflection file 졸리운_곰 2015.10.14 61
136 Serializable 객체직렬화 file 졸리운_곰 2015.10.14 256
135 Java Serialization 알자 졸리운_곰 2015.10.14 464
134 Eclipse RCP Tutorial: Eclipse Rich Client Application with a View file 졸리운_곰 2015.10.05 383
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED