Java 반사 (JAVA 반사) 상세 해석 (2)

이 정 보 를 얻 으 면 세 번 째 단 계 를 진행 할 수 있 습 니 다. reflection API 를 사용 하여 이 정 보 를 조작 할 수 있 습 니 다. 예 를 들 어 다음 코드 와 같 습 니 다.
  Class c = Class.forName("java.lang.String");
  Method m[] = c.getDeclaredMethods();
  System.out.println(m[0].toString());
String 에서 정의 하 는 첫 번 째 방법의 원형 을 텍스트 로 출력 합 니 다.
아래 의 예 에서 이 세 단 계 는 reflection 을 사용 하여 특수 응용 프로그램 을 처리 하 는 데 예증 을 제공 할 것 이다.
아 날로 그 instanceof 연산 자
클래스 정 보 를 얻 은 후에 보통 다음 단 계 는 Class 대상 에 관 한 기본 적 인 문 제 를 해결 하 는 것 이다.예 를 들 어 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 대상 을 만 든 다음 일부 대상 이 A 의 인 스 턴 스 인지 확인 합 니 다.Integer (37) 는 아니 지만 new A () 는.
3. 종 류 를 찾 는 방법
클래스 에서 어떤 방법 을 정 의 했 는 지 찾 는 것 은 매우 가치 있 고 매우 기본 적 인 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);
}
}
}


이 프로그램 은 먼저 method 1 류 의 설명 을 얻 은 다음 에 getDeclared Methods 를 호출 하여 일련의 Method 대상 을 얻 습 니 다. 그들 은 각각 클래스 에 정 의 된 모든 방법 을 묘 사 했 습 니 다. 이 는 Public 방법, proctected 방법, package 방법 과 private 방법 등 을 포함 합 니 다.만약 프로그램 에서 getMethods 를 사용 하여 getDeclared Methods 를 대체 한다 면, 계승 하 는 각 방법의 정 보 를 얻 을 수 있 습 니 다.
Method 대상 목록 을 가 져 온 후 이 방법의 매개 변수 유형, 이상 유형, 반환 값 형식 등 을 표시 하 는 것 은 어렵 지 않 습 니 다.이 유형 들 은 기본 유형 인지 유형 인지 설명 류 의 대상 이 순서대로 제시 할 수 있다.
출력 결 과 는 다음 과 같 습 니 다.

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

4. 구조 기 정보 가 져 오기
클래스 구조 기 를 가 져 오 는 방법 은 상기 획득 방법 과 유사 합 니 다. 예 를 들 어:
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





5. ( )


클래스 에서 어떤 데이터 필드 를 정의 하 는 지 찾 는 것 도 가능 합 니 다. 아래 코드 는 바로 이 일 을 하고 있 습 니 다.

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 를 사 용 했 습 니 다. 이것 은 reflection 류 로 필드 구성원 의 수식 어 를 설명 합 니 다. 예 를 들 어 "private int"와 같 습 니 다.이 수식어 자체 가 정수 로 설명 되 고 Modifier. toString 을 사용 하여 '공식' 순서 로 배 열 된 문자열 설명 을 되 돌려 줍 니 다 (예 를 들 어 'static' 이 'final' 이전에).이 프로그램의 출력 은:

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 =


가 져 오 는 방법 과 함께 필드 를 가 져 올 때 현재 클래스 에 명 시 된 필드 정보 (getDeclared Fields) 만 얻 거나 부모 클래스 에서 정 의 된 필드 (getFields) 를 얻 을 수 있 습 니 다.
6. 방법의 명칭 에 따라 실행 방법
텍스트 가 여기까지 왔 습 니 다. 예 를 들 면 클래스 의 정 보 를 어떻게 얻 는 지 와 관련 이 있 습 니 다.우 리 는 이름 을 지정 한 방법 을 실행 하 는 등 reflection 으로 다른 일 을 할 수 있다.다음 예제 에서 이 동작 을 보 여 줍 니 다.

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);
}
}
}


만약 에 프로그램 이 실행 되 는 어 딘 가 에서 어떤 방법 을 실행 해 야 한 다 는 것 을 알 게 된다 면 이 방법의 이름 은 프로그램의 실행 과정 에서 지정 한 것 입 니 다 (예 를 들 어 자바 빈 개발 환경 에서 이런 일 을 할 것 입 니 다). 그러면 위의 프로그램 은 어떻게 하 는 지 보 여 줍 니 다.
상례 에서 getMethod 는 두 개의 정형 파 라미 터 를 가지 고 있 으 며 add 라 는 방법 을 찾 는 데 사 용 됩 니 다.이 방법 을 찾 아 해당 Method 대상 을 만 든 후 정확 한 대상 인 스 턴 스 에서 실행 합 니 다.이 방법 을 실행 할 때 매개 변수 목록 을 제공 해 야 합 니 다. 이 는 상기 사례 에서 정수 37 과 47 의 두 개의 Integer 대상 을 각각 포장 한 것 입 니 다.실행 방법 을 되 돌려 주 는 것 은 Integer 대상 으로 되 돌아 오 는 값 84 를 패키지 합 니 다.
7. 새로운 대상 만 들 기
구조 기 에 대해 서 는 실행 방법 처럼 진행 할 수 없습니다. 구조 기 를 실행 하 는 것 은 새로운 대상 을 만 드 는 것 을 의미 하기 때 문 입 니 다 (정확히 말 하면 대상 을 만 드 는 과정 은 메모리 와 구조 대상 을 분배 하 는 것 을 포함 합 니 다).그래서 상례 와 가장 비슷 한 예 는 다음 과 같다.
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);
}
}
}

지정 한 매개 변수 형식 에 따라 해당 하 는 구조 함 수 를 찾 아 실행 하여 새로운 대상 인 스 턴 스 를 만 듭 니 다.이 방법 을 사용 하면 프로그램 이 실 행 될 때 대상 을 동적 으로 만 들 수 있 습 니 다. 컴 파일 할 때 대상 을 만 드 는 것 이 아니 라 매우 가치 가 있 습 니 다.
8. 필드 (도 메 인) 의 값 변경
reflection 의 또 다른 용 도 는 대상 데이터 필드 의 값 을 바 꾸 는 것 이다.reflection 은 실행 중인 프로그램 에서 이름 에 따라 대상 의 필드 를 찾 아 변경 할 수 있 습 니 다. 아래 의 예 는 이 점 을 설명 할 수 있 습 니 다.
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);
}
}
}

이 예 에서 필드 d 의 값 은 12.34 로 바 뀌 었 습 니 다.
9. 배열 사용
본 고 에서 소개 한 reflection 의 마지막 용법 은 만 든 조작 배열 이다.배열 은 자바 언어 에서 특수 한 유형 으로 한 배열 의 인용 은 Object 에 인용 할 수 있 습 니 다.다음 의 예 를 들 어 배열 이 어떻게 일 하 는 지 살 펴 보 자.
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);
}
}
}

예 를 들 어 10 개의 단위 길이 의 String 배열 을 만 들 었 습 니 다. 다섯 번 째 위치의 문자열 에 값 을 부여 하고 마지막 으로 이 문자열 을 배열 에서 가 져 와 인쇄 했 습 니 다.
다음 코드 는 더욱 복잡 한 예 를 제공 합 니 다.
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]);
}
}

예 를 들 어 5 x 10 x 15 의 전체 배열 을 만 들 었 고 [3] [5] [10] 에 있 는 요소 에 값 을 37 로 부 여 했 습 니 다. 다 차원 배열 은 실제 적 으로 배열 의 배열 입 니 다. 예 를 들 어 첫 번 째 Array. get 이후 arrobj 는 10 x 15 의 배열 입 니 다.더 나 아가 그 중의 한 요소, 즉 길이 가 15 인 배열 을 얻 고 Array. setInt 를 사용 하여 10 번 째 요소 에 값 을 부여 합 니 다.
배열 을 만 들 때 형식 이 동적 이 고 컴 파일 할 때 형식 을 모 릅 니 다.

좋은 웹페이지 즐겨찾기