1. 정의

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

형은 알고 있지만 형변환을 할 수 없는 상태에서 객체의 메소드를 호출할 수 있음


자바에서는 클래스의 정보를 분석하기 위한 도구로 Class 클래스를 제공해주고 있는데, .class의 등록 정보 클래스, 바이트 코드의 등록 정보 클래스로 표현할 수 있다.


Class 클래스는 java.lang 패키지 소속의 클래스이며 Method, Field, Constructor는 java.lang.reflect 패키지에 존재한다.

그렇기 때문에 자바의 리플렉션 기법을 사용하기 위해서는 무조건 java.lang.reflect 패키지를 import 한 후에 사용해야 한다.



2. 정적 바인딩

컴파일시 이미 컴파일러가 Data 클래스를 알고 있는 상태(class path가 지정된 곳에 클래스 자체가 존재해야 함)

컴파일 시점에 이미 로딩되어 있음 (ex. new 연산자)

다운 캐스팅도 가능하고 마음대로 Data라는 형을 사용할 수 있음


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.example;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class ShowClassInfoMain {
    public static void main(String[] args) {
//      Integer 클래스 데이터 타입을 Class 클래스 데이터 타입 c로 값 복사
//      Integer 클래스는 java.lnag 패키지 소속이기 때문에 자동 import
        Class c = Integer.class;
        
//      클래스, 생성자, 메소드, 필드명 객체 주소 알아내기(여러개일 수 있으므로 배열로 받는다)
        Class[] iface = c.getInterfaces();
        Constructor [] ctor = c.getConstructors();
        Method [] m = c.getMethods();
        Field[] f = c.getFields();
        
//      Integer 클래스 타입인 c를 Class타입인 temp로 값 복사함
        Class temp = c;
        
//      temp와 temp.getSuperClass. 상위 클래스의 값이 null이 아닌 경우 무한 반복
//      (상위 클래스들을 모두 역으로 추적하기 위해 while문 사용함)
//      => 상위 클래스 : Number, Object (콘솔 창에 출력되는 결과)
        while ( (temp = temp.getSuperclass()) != null) {
            System.out.println(temp);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 인터페이스 배열들 출력하는 for문
        for (int i = 0; i < iface.length; i++) {
            System.out.println("interface[" + i + "] = " + iface[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 생성자 배열들 출력하는 for문
        for (int i = 0; i < ctor.length; i++) {
            System.out.println("Constructor[" + i + "] = " + ctor[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 메소드 배열들 출력하는 for문
        for (int i = 0; i < m.length; i++) {
            System.out.println("Methoid[" + i + "] = " + m[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 필드 배열들 출력하는 for문
        for (int i = 0; i < f.length; i++) {
            System.out.println("Field[" + i + "] = " + f[i]);
        }
    }
}
cs

<클래스 정보 출력하는 예제>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.example;
 
//정적 바인딩을 이용해 다운 캐스팅 하는 클래스
public class Data {
    public void sayHello() {
        System.out.println("Hello World!");
    }
}
 
package com.example;
 
public class StaticBindingMain {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//      정적 바인딩으로 Data 클래스를 사용함
//      정적 바인딩 : 개발자가 .class 파일을 직접 로딩한 후 Class 클래스를 이용하여 객체를 생성하면
//                    JVM이 그 다음 작업을 해주는 것
//      1단계 > .class : 개발자가 .class 파일을 직접 로딩하여 Class 클래스에 값 복사함
        Class c = Data.class;
//      2단계 > newInstance() : Class 클래스 이용하여 객체를 직접 생성하는 메소드
//                         (정적 바인딩을 직접 하기 위해)
        Object obj = c.newInstance();
        
//      정적 바인딩으로 Data 클래스를 사용함
//      (Data 라는 해당 클래스가 프로젝트 안에 실제로 존재해야 함)
        Data d = (Data) obj;
        Class c2 = d.getClass();
        
//      정적 바인딩으로 Data 클래스를 사용함
        Data d2 = (Data) c2.newInstance();
        
        System.out.println(d);
        System.out.println(d2);
        
        d.sayHello();
        d2.sayHello();
    }
}
cs

<정적 바인딩 예제>



3. 동적 바인딩

일반적으로 말하는 리플렉션의 기법

런타임(실행) 시점에 로딩되기 때문에 컴파일 시에는 해당 클래스가 없어도 됨

프로그램이 실행되고 난 뒤 동적으로 위치를 명시하고, 해당 클래스( .class) 를 로딩하여 객체를 만들고 메소드를 호출함

해당 클래스가 바로 존재하지 않아도 클래스의 위치와 이름만 알면 찾을 수 있음 (ex. Class.forName(String str))


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.example;
 
public class DynamicData {
    public void sayHello() {
        System.out.println("안녕하세요!");
    }
    
    public void goodBye() {
        System.out.println("안녕히계세요!");
    }
}
 
package com.example;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
 
public class DynamicDataClassMain {
    public static void main(String[] args) throws IOException, InstantiationException, 
                                                    IllegalAccessException, ClassNotFoundException {
        System.out.println("다운로드중 ...");
        
//      웹 서버에 존재하는 파일에 연결된 스트림을 생성하는 방법
        URL url = new URL("http://www.jabook.org/DynamicData.class");
        InputStream is = url.openStream();
        
//      스트림을 통해 읽은 데이터를 저장하기 위해 파일 출력 스트림 생성
        FileOutputStream fos = new FileOutputStream("DynamicData.class");
        
        int i;
        
//      입력 & 출력 스트림이 생성되었을 시 반복
        while ( (i = is.read()) != -1) {
            fos.write(i);
            
            System.out.println("|");
        }
        
//      열어놨던 입출력 스트림들은 반드시 닫아줘야 함
        fos.close();
        is.close();
        
        System.out.println("\n 다운로드 완료 ...");
        
//      클래스의 이름 자체를 컴파일 타임에 사용할 수 없기 떄문에 문자열 형태로 클래스의 이름을 사용
//      Class.forName(String str)이 호출되는 그 순간 클래스를 로딩하겠다는 의미
//      매개변수가 String 형인 이유 : 해당 클래스가 컴파일시 없기 때문
        Class c = Class.forName("DynamicData");
        
//      동적으로 생성된 Class 정보를 이용해서 객체 생성
        Object obj = c.newInstance();
        
        System.out.println(obj);
        
        /*
         * 정적 바인딩과 동적 바인딩의 차이
         * - 다운 캐스팅의 유무 (동적 바인딩 : X, 정적 바인딩 : O)
         * - 이유 : 동적 바인딩은 컴파일시 해당 클래스의 이름을 사용할 수 없기 때문임
         *             (매개변수로 클래스 이름을 넣는게 아니라 위치만 넣으니까)
         *             동적 바인딩은 멤버 메소드를 호출할 수 없다
         * 
         *     (중요) => 이 때, java.lang.Reflection 패키지의 Class 클래스를 이용하여
         *            다운캐스팅 할 수 없는 객체여도 모든 작업을 할 수 있게 지원해줌 (ex. getContstructors())
         */           
    }
}
cs

<동적 바인딩 예제>

'BackEnd > Java' 카테고리의 다른 글

자바 기본 정리  (0) 2017.02.09
Java :: startsWith() vs indexOf() vs charAt()  (0) 2016.12.26
Java :: Exception 예외처리  (0) 2016.12.15
Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22
Java :: Abstract vs Interface  (0) 2016.10.28

+ Recent posts