Reflection in Java
反射是一种API,用于在运行时检查或修改方法,类,接口的行为。
- 反射所需的类在java.lang.reflect包下提供。
- 反射为我们提供了有关对象所属类的信息,以及可以使用该对象执行的该类的方法。
- 通过反射,我们可以在运行时调用方法,而与它们所使用的访问说明符无关。
反射可用于获取有关–的信息
- 用于获取对象所属的类的名称
- 构造函数 getConstructors()方法用于获取对象所属类的公共构造函数
- 方法 getMethods()方法用于获取对象所属类的公共方法
public class ReflectionTest {
private String s;
public ReflectionTest(){
this.s="init ReflectionTest class field";
}
public void method1(){
System.out.println("The String for ReflectionTest s value:" + s);
}
public void method2(int num){
System.out.println("The method2 param incoming is "+ num);
}
private void method() {
System.out.println("private method invoked");
}
}
public class DemoTestMain {
public static void main(String[] args) throws Exception {
//to create a tested class object
ReflectionTest refObj = new ReflectionTest();
//1. 通过getClass获取类对象
Class<?> cls = refObj.getClass();
//2.通过字节码获取对象
//Class<?> cls2 = ReflectionTest.lcass;
//3.通过Class.forName获取对象
//Class<?> cls3 = Class.forName("com.demo.ReflectionTest");
System.out.println("The name for the obj is " + cls.getName());
System.out.println("The method for this obj ");
//get constructor for the class
Constructor constructor = cls.getConstructor();
System.out.println("The name for class constructor is "+constructor.getName());
//get all the method for this Class obj
Method[] methods = cls.getMethods();
//for Each all the method
for (int i = 0; i < methods.length; i++) {
System.out.println("for the class object method " + methods[i]);
}
//get specified method
Method speMethod = cls.getMethod("method2", int.class);
System.out.println("specified method name is " + speMethod.getName());
// invoke specified method
speMethod.invoke(refObj, 10);
//get desired field for the class
Field sFiled = cls.getDeclaredField("s");
//allow the object to access the filed,because the field was private
sFiled.setAccessible(true);
sFiled.set(refObj,"Java Reflection Demo");
//get desired method for the class
Method method2 = cls.getDeclaredMethod("method2", int.class);
method2.invoke(refObj,99);
}
}
输出:
The name for the obj is com.seny.test.ReflectionTest
The method for this obj
The name for class constructor is com.seny.test.ReflectionTest
for the class object method public void com.seny.test.ReflectionTest.method2(int)
for the class object method public void com.seny.test.ReflectionTest.method1()
for the class object method public final void java.lang.Object.wait() throws java.lang.InterruptedException
for the class object method public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
for the class object method public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
for the class object method public boolean java.lang.Object.equals(java.lang.Object)
for the class object method public java.lang.String java.lang.Object.toString()
for the class object method public native int java.lang.Object.hashCode()
for the class object method public final native java.lang.Class java.lang.Object.getClass()
for the class object method public final native void java.lang.Object.notify()
for the class object method public final native void java.lang.Object.notifyAll()
specified method name is method2
The method2 param incoming is 10
The method2 param incoming is 99
重要观察:
如果知道方法的名称和参数类型,则可以通过反射调用该方法。为此,我们使用以下两种方法
getDeclaredMethod():创建要调用的方法的对象。该方法的语法是
Class.getDeclaredMethod(name,parameterType)
name-要创建其对象的方法的名称
parameterType-参数是Class对象的数组
invoke():要在运行时调用类的方法,我们使用以下方法–
Method.invoke(Object,parameter)
如果该类的方法不接受任何方法参数,则将null用作参数。
通过反射,我们可以在类的类对象的帮助下访问类的私有变量和方法,并使用对象来调用方法,如上所述。为此,我们使用以下两种方法。
Class.getDeclaredField(FieldName):用于获取私有字段。返回指定类型字段名称的对象。
Field.setAccessible(true):允许访问该字段,而与该字段使用的访问修饰符无关。
使用反射的优势:
- 可扩展性功能:应用程序可以通过使用其完全限定的名称创建可扩展性对象的实例来使用外部的用户定义类。
- 调试和测试工具:调试器使用反射的特性去检测类的私有成员。
缺点:
- 性能开销:反射性操作的性能比非反射性操作慢,因此应避免在对性能敏感的应用程序中对于经常调用的代码段要尽量避免使用反射操作。
- 内部暴露:反射代码破坏了抽象,因此可能会随着平台升级而改变行为。