在 Java 语言中,反射机制是指对于处在运行状态中的类,都能够获取到这个类的所有属性和方法。
对于任意一个对象,都能够调用它的任意一个方法以及访问它的属性;这种通过动态获取类或对象的属性以及方法从而完成调用功能被称为 Java 语言的反射机制。它主要实现了以下功能:
在反射机制中 Class 是一个非常重要的类,在 Java 语言中获取 Class 对象主要有如下几种方法:
class A {
static {
System.out.println("static block");
}
{
System.out.println("dynamic block");
}
}
class Test {
public static void main(String[] args) {
Class<?> c = A.class;
System.out.println("className:" + c.getName());
}
}
运行结果为:
className:A
public static void main(String[] args) {
Class<?> c = null;
try {
c = Class.forName("A");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("className:" + c.getName());
}
运行结果为:
static block
className:A
public static void main(String[] args) {
Class<?> c = new A().getClass();
System.out.println("className:" + c.getName());
}
运行结果为:
Static block
dynamic block
className:A
从上面的例子可知,虽然这三种方式都可以够获得 Class 对象,但是它们还是有区别的,区别如下:
Class 类提供了非常多的方法,下面给出三类常用的方法:
构造方法的封装类为Constructor,Class 类中有如下四个方法来获得 Constructor 对象:
成员变量的封装类为Field类,Class 类提供了以下四个方法来获取 Field 对象:
Java 代码如下:
import java.lang.reflect.*;
public class Test {
protected Test() {
System.out.println("Protected constructor");
}
public Test(String name) {
System.out.println("Public constructor");
}
public void f() {
System.out.println("f()");
}
public void g(int i) {
System.out.println("g(): " + i);
}
/*内部类*/
class Inner {
}
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("Test");
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
System.out.println("Test类的构造函数:");
for (Constructor<?> c : constructors) {
System.out.println(c);
}
Method[] methods = clazz.getMethods();
System.out.println("Test 的全部 public 方法:");
for (Method md : methods) {
System.out.println(md);
}
Class<?>[] inners = clazz.getDeclaredClasses();
System.out.println("Test 类的内部类为:");
for (Class<?> c : inners) {
System.out.println(c);
}
}
}
运行结果为:
Test类的构造函数:
protected Test()
public Test(java.lang.String)
Test 的全部 public 方法:
public static void Test.main(java.lang.String[]) throws java.lang.Exception
public void Test.g(int)
public void Test.f()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
Test 类的内部类为:
class Test$Inner
引申:有如下代码:
class ReadOnlyClass{
private Integer age = 20;
public Integer getAge() { return age;}
}
现给定一个 ReadOnlyClass 的对象 roc,能否把这个对象的 age 值改成 30?
答案:从正常编程的角度出发分析,会发现在上述代码中,age 属性被修饰为 private,而且这个类只提供了获取 age 的 public 的方法,而没有提供修改 age 的方法,因此,这个类是一个只读的类,无法修改 age 的值。但是 Java 语言还有一个非常强大的特性:反射机制。所以,本题中,可以通过反射机制来修改 age 的值。
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取对象的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。Java 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的 class。换句话说,Java 可以加载一个运行时才得知名称的 class,获得其完整结构。
在 Java 语言中,任何一个类都可以得到对应的 Class 实例,通过 Class 实例就可以获取类或对象的所有信息,包括属性(Field 对象)、方法(Method 对象)或构造方法(Constructor对象)。
对于本题而言,在获取到 ReadOnlyClass 类的 class 实例以后,就可以通过反射机制获取到 age 属性对应的 Field 对象,然后可以通过这个对象来修改 age 的值。Java 代码如下:
import java.lang.reflect.Field;
class ReadOnlyClass {
private Integer age = 20;
public Integer getAge() {
return age;
}
}
public class Test {
public static void main(String[] args) throws Exception {
ReadOnlyClass pt = new ReadOnlyClass();
Class<?> clazz = ReadOnlyClass.class;
Field field = clazz.getDeclaredField("age");
field.setAccessible (true);
field.set(pt, 30);
System.out.println(pt.getAge());
}
}
运行结果为:
30