能够分析类能力的程序称为反射(reflective)。反射机制的功能极其强大,反射机制可以用来:(1)在运行时分析类的能力。 (2)在运行时查看对象, 例如, 编写一个 toString方法供所有类使用。s(3)实现通用的数组操作代码。 (3)利用 Method 对象, 这个对象很像cpp中的函数指针。
通过代码分析展示反射的作用。
首先创建com.reflectTest
包下Test.java
、Fa.java
、Son.java
三个类文件。代码如下:Test.java
根据具体样例给出。
Fa.java
package com.reflectTest;
public class Fa {
public final int a = 1;
}
Son.java
package com.reflectTest;
public class Son extends Fa{
private double b = 2.0;
public static int maxn = 1000;
public Son() {}
public Son(double b) {
this.b = b;
}
public void sonFunc(String s) {
System.out.println(s);
}
}
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。 这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。
然而, 可以通过专门的 Java 类访问这些信息。保存这些信息的类被称为 Class, 这个名 字很容易让人混淆。Object 类中的 getClass( ) 方法将会返回一个 Class 类型的实例。
Object
的getClass
方法可以获得一个对象的类,这是一个本地方法。Class
的getName
方法,可以获得类的名字。Test.java
代码如下:
package com.reflectTest;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class c = new Son().getClass(); //通过Object类的getClass方法获得一个Class对象
System.out.println(c);
System.out.println(c.getName()); //getName()方法返回类的名字
}
}
Class
的静态方法forName
,通过输入的字符串获得一个Class
对象,该方法可能抛出一个ClassNotFoundException
异常。Class
的newInstance
方法,调用类的无参构造方法构造一个对象,该方法不能调用有参数构造方法。(Constructor
的 newInstance
方法可以调用有参构造方法)方法可能抛出IllegalAccessException
与InstantiationException
异常。Class
的getSuperclass
方法,返回该Class
对象的父类(不是返回Class
类的父类)Test.java
代码如下:
package com.reflectTest;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String className = "com.reflectTest.Son"; //使用forName构建一个Class对象表示Son类
Class c = Class.forName(className); //可能抛出ClassNotFoundException
double[] b = new double[0];
Son s = (Son) c.newInstance();
System.out.println(c.getName()); //输出Son类的类名
System.out.println(c.getSuperclass().getName()); //输出Son类父类的类名
}
}
通过以下代码的输出结果为true可以验证。(怎么实现的。为什么?)
package com.reflectTest;
public class Test {
public static void main(String[] args) {
Class c1 = Fa.class;
Class c2 = new Fa().getClass();
Class c3 = new Fa().getClass();
System.out.println(c1 == c2 && c2 == c3);
}
}
在
java.lang.reflect
包中有三个类Field
、Method
、Constructor
分别用于描述类的域、方法和构造器。下面一步一步分析这三个类的作用。
Class
、Field
、Method
、Constructor
这几个类均有getModifiers
方法返回一个整数(表示修饰符),利用java.lang.reflett
包中的Modifier
类的静态方法toString
分析getModifiers
返回的整型数值。如下代码:Test.java
package com.reflectTest;
import java.lang.reflect.Modifier;
public final class Test {
public static void main(String[] args) throws ClassNotFoundException {
String className = "com.reflectTest.Son";
Class c = Class.forName(className);
String modifier = Modifier.toString(c.getModifiers()); //分析类
System.out.println(modifier); //Son类的修饰符是public
System.out.println(Modifier.toString(Class.forName("com.reflectTest.Test").getModifiers()));
}
}
Class
类的getFields
、getConstructors
、getMethods
方法可以获得Field
、Constructor
、Method
对象,但是只能获得public
的。Class
类的getDeclaredFields
、getDeclaredConstructors
、getDeclaredMethods
方法可以获得Field
、Constructor
、Method
对象,但是不能获得父类的。Test.java
package com.reflectTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public final class Test {
public int a = 1;
private int b = 1;
public Test() {}
private Test(int a) {}
public void func1() {}
private void func2() {}
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("com.reflectTest.Test");
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors)
System.out.println(constructor.getName());
Field[] fields = c.getDeclaredFields();
for (Field field : fields)
System.out.println(field.getName());
Method[] methods = c.getDeclaredMethods();
for (Method method : methods)
System.out.println(method.getName());
}
}
Method
的getReturnType
方法可以获得返回值Class
对象。Method
的getParameterTypes
方法可以获得函数的参数Class
对象列表。package com.reflectTest;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public final class Test {
public int func1(int a,double b) {return 0;}
private boolean func2(boolean c) {return true;}
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("com.reflectTest.Test");
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
String modifiers = Modifier.toString(method.getModifiers());
System.out.print(modifiers + " " + method.getReturnType().getName() + " ");
System.out.print(method.getName() + "(");
Class[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (i == 0) System.out.print(parameters[i].getName());
else System.out.print(", " + parameters[i].getName());
}
System.out.println(")");
}
}
}
Field
对象,然后通过get
获得对象的域中的值,或者通过set
方法修改域中的值。Class
对象的getDefaulted方法才能获得所有修饰符中的对象(如private),而获取private
域的值时,需要调用Field
、Method
、Constructor
的setAccess
方法设置访问控制权限。Test.java
package com.reflectTest;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
GetTest gt = new GetTest();
Class c = gt.getClass();
//获得s1域
Field field1 = c.getField("s1");
System.out.println(field1.get(gt));
//获得s2域(因为不是public,所以需要用getDeclaredField而不是get)
Field field2 = c.getDeclaredField("s2");
//设置访问方法,否则(private)域不能访问。
field2.setAccessible(true);
System.out.println(field2.get(gt));
//设置gt的field2域的值为"ccccc"
field2.set(gt, "ccccc");
System.out.println(gt.getS2());
}
}
class GetTest {
public String s1 = "aaaaa";
private String s2 = "bbbbb";
public String getS2() {
return s2;
}
}