public class Calculator {
public int result = 0;
public void calculate(int a, int b) {
result = a + b;
}
}
public class AddCalculator extends Calculator {
public void print(int a, int b) {
calculate(a, b);
System.out.println("result = " + result);
}
public int getResult() {
return result;
}
}
public static void main(String[] args) {
Calculator calculator = new AddCalculator();
// calculator.print(); -> 컴파일 에러
}
자바는 컴파일러를 사용하고, 컴파일 타임에 변수의 타입이 결정된다. calculator
는 컴파일 타임에 Calculator
로 타입이 결정되었기 때문에 AddCalculator
의 필드와 메서드는 사용하지 못한다.
Reflection API를 사용하면 Calculator
타입의 calculator
가 AddCalculator
의 메서드를 호출할 수 있게 해준다.
public static void main(String[] args) {
Calculator calculator = new AddCalculator();
Class addCalculatorClass = AddCalculator.class;
Method print = addCalculatorClass.getMethod("print");
Object[] params = new Object[2];
params[0] = new Integer(1);
params[1] = new Integer(2);
// 메서드명.invoke(메서드를 실행시킬 객체, 메서드에 넘길 인자)
print.invoke(calculator, params); // result = 3
Method getResult = addCalculatorClass.getMethod("getResult");
int result = (int) getResult.invoke(calculator, null);
System.out.println(result); // 3
}
calculator
가 구체적인 클래스 타입인 AddCalculator
를 알지 못해도 메서드에 접근하였다.
어플리케이션 개발보다 프레임워크, 라이브러리에 사용된다.
사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection API 사용
우리가 코드를 작성하면서 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)
Class c = Class.forName("java.lang.String");
Class c = int.class;
Class c = Integer.TYPE;
getDeclaredMethods()
등 호출Class.isInstance()
class A {}
public class InstanceOperator {
public static void main(String args[]) {
try {
Class cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37)); // false
System.out.println(b1);
boolean b2 = cls.isInstance(new A()); // true
System.out.println(b2);
} catch (Throwable e) {
System.err.println(e);
}
}
}
클래스에서 정의한 메서드가 무엇인지 찾아내기 → reflection의 가장 기초 쓰임
import java.lang.reflect.*;
public class CheckMethod {
private int check(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("CheckMethod");
Method[] methods = cls.getDeclaredMethods();
for (int i = 0; i < methods .length; i++) {
Method method = methods [i];
System.out.println("method name = " + method.getName());
System.out.println("declaring class = " + method.getDeclaringClass());
Class[] parameterTypes = method.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++)
System.out.println(" param #" + j + " " + parameterTypes[j]);
Class[] exceptions = method.getExceptionTypes();
for (int j = 0; j < exceptions.length; j++)
System.out.println("exception #" + j + " " + exceptions[j]);
System.out.println("return type = " + method.getReturnType());
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
<실행 결과>
method name = check
decl class = class CheckMethod
param #0 class java.lang.Object
param #1 int
exception #0 class java.lang.NullPointerException
return type = int
-----
name = main
decl class = class CheckMethod
param #0 class [Ljava.lang.String;
return type = void
-----
import java.lang.reflect.*;
public class ContrutorReflection {
public ContrutorReflection() {
}
protected ContrutorReflection(int i, double d) {
}
public static void main(String args[]) {
try {
Class cls = Class.forName("ContrutorReflection");
Constructor[] constructors = cls.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
System.out.println("constructor name = " + constructor.getName());
System.out.println("declaring class = " + constructor.getDeclaringClass());
Class[] params = constructor.getParameterTypes();
for (int j = 0; j < params.length; j++)
System.out.println("param #" + j + " " + params[j]);
Class[] exceptions = constructor.getExceptionTypes();
for (int j = 0; j < exceptions.length; j++)
System.out.println("exception #" + j + " " + exceptions[j]);
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
<실행 결과>
contructor name = ContrutorReflection
declaring class = class ContrutorReflection
-----
contructor name = ContrutorReflection
declaring class = class ContrutorReflection
param #0 int
param #1 double
-----
private int
필드를 표현하기 위한 reflection classModifier.toString()
: static과 final과 같은 키워드의 선언 순서의 문자열 표현 리턴import java.lang.reflect.*;
public class FieldReflection {
public static final int i = 37;
private doubld d;
String str = "testing";
public static void main(String args[]) {
try {
Class cls = Class.forName("FieldReflection");
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields .length; i++) {
Field field = fields[i];
System.out.println("field name = " + field.getName());
System.out.println("declaring class = " + field.getDeclaringClass());
System.out.println("type = " + field.getType());
int modifier = field.getModifiers();
System.out.println("modifiers" + Modifier.toString(modifier));
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
<실행 결과>
name = d
decl class = class FieldReflection
type = double
modifiers = private
-----
name = i
declaring class = class FieldReflection
type = int
modifiers = public static final
-----
name = str
declaring class = class FieldReflection
type = class java.lang.String
modifiers =
-----
import java.lang.reflect.*;
public class MethodReflection {
public int add(int a, int b) {
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName("MethodReflection");
Class[] paramtypes = new Class[2];
paramtypes[0] = Integer.TYPE;
paramtypes[1] = Integer.TYPE;
Method method = cls.getMethod("add", paramtypes);
MethodReflection methodReflection = new MethodReflection();
Object[] params = new Object[2];
params[0] = new Integer(37);
params[1] = new Integer(47);
Object result = method.invoke(methodReflection, params);
Integer resultValue = (Integer) result;
System.out.println(resultValue.intValue());
} catch (Throwable e) {
System.err.println(e);
}
}
}
import java.lang.reflect.*;
public class ContructorReflection {
public ConstructorReflection() {
}
public ConstructorReflection(int a, int b) {
System.out.println("a = " + a + " b = " + b);
}
public int add(int a, int b) {
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName("ConstructorReflection");
Class[] paramtypes = new Class[2];
paramtypes[0] = Integer.TYPE;
paramtypes[1] = Integer.TYPE;
Contructor constructor = cls.getContructor(paramtypes);
Object[] params = new Object[2];
params[0] = new Integer(37);
params[1] = new Integer(47);
Object result = contructor.newInstance(params);
} catch (Throwable e) {
System.err.println(e);
}
}
}
import java.lang.reflect.*;
public class FieldReflection {
public double d;
public static void main(String args[]) {
try {
Class cls = Class.forName("FieldReflection");
Field field = cls.getField("d");
FieldReflection fieldReflection = new FieldReflection();
System.out.println("d = " + fieldRelection.d);
field.setDouble(fieldReflection, 12.34);
System.out.println("d = " + fieldReflection.d);
} catch (Throwable e) {
System.err.println(e);
}
}
}
import java.lang.reflect.*;
public class ArrayReflection {
public static void main(String args[]) {
try {
Class cls = Class.forName("java.lang.String");
Object array = Array.newInstance(class, 10);
Array.set(array, 5, "array test");
String str = (Stirng) Array.get(array, 5);
System.out.println(str);
} catch (Throwable e) {
System.err.println(e);
}
}
}