反射机制作用:
1.在运行中分析类的能力;
2.在运行中查看对象;
3.实现通用的数组操作代码;
4.利用Method对象操作函数;
5.利用Field对象操作属性。
使用反射机制主要用于工具构造者,而不是应用程序员。
定义一个在运行中反射的类:ReflectClass.java
package com.ez;
import java.io.Serializable;
import java.util.RandomAccess;
//这三个接口并不需要实现任何方法,所以就当测试吧。
public class ReflectClass implements Serializable, RandomAccess, Cloneable {
private static final long serialVersionUID = -428410635246468432L;
private String name;
private int age;
private int money;
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
// 在反射条用方法的时候,无参构造函数不能省略,否则报错。
public ReflectClass() {
}
// 至少有一个name属性
// 年纪默认20
// 工资默认2000
public ReflectClass(String name) {
this(name, 20);
}
public ReflectClass(String name, int age) {
this(name, age, 2000);
}
public ReflectClass(String name, int age, int money) {
this.name = name;
this.age = age;
this.money = money;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getMoney() {
return money;
}
public void doubleSalary() {
this.money = money * 2;
}
// 添加下面两个方法供反射机制调用方法
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
@Override
public String toString() {
return "[name:" + name + "\n" + //
"age:" + age + "\n" + //
"money:" + money + "]\n";//
}
}
编写一个运行类:Main.java
package com.ez;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main {
public static void main(String[] args) throws Exception {
// 1、通过实例对象获取包名
ReflectClass test = new ReflectClass("luopan");
System.out.println(test.getClass().getName());// 输出:com.ez.ReflectClass
// 2、定义三个类对象,通过三种方式获取对象实例
Class<?> class1 = null;
Class<?> class2 = null;
Class<?> class3 = null;
class1 = Class.forName("com.ez.ReflectClass");
class2 = new ReflectClass("weize").getClass();
class3 = ReflectClass.class;
System.out.println("class1=" + class1.getName());// 输出:class1=com.ez.ReflectClass
System.out.println("class2=" + class2.getName());// 输出:class2=com.ez.ReflectClass
System.out.println("class3=" + class3.getName());// 输出:class3=com.ez.ReflectClass
// 3、获得父类信息【父类只有一个】
Class<?> parentClass = class1.getSuperclass();
System.out.println("parentClass=" + parentClass.getName());// 输出:parentClass=java.lang.Object
// 4、获得接口信息【接口有多个,所以自然而然是一个数组了】
Class<?>[] interfaces = class1.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
System.out.printf("interface%d=%s \n", i + 1, interfaces[i]);
}
// 5、获取全部的构造方法【构造函数数量不是唯一的,所以是一个数组】
Constructor<?> constructor[] = class1.getConstructors();
for (int i = 0; i < constructor.length; i++) {
// 遍历每个构造函数,并且获取到每个构造函数的参数类型。【由于参数格式不是唯一的,所以是一个数组】
Class<?> clazz[] = constructor[i].getParameterTypes();
for (int j = 0; j < clazz.length; j++) {
if (j == clazz.length - 1)
System.out.print(clazz[j].getName());
else
System.out.print(clazz[j].getName() + ",");
}
System.out.println();
}
// 6、根据获取得到的构造函数个数以及参数类型,实例化对象
// 由于构造函数的顺序不是固定的,所以可以根据控制台打印的信息,手动创建实例对象
// 7、获取全部属性【属性数量不唯一,所以是数组】
Field[] field = class1.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 每个属性都是由权限修饰符和类型组成
int mo = field[i].getModifiers();
String modiString = Modifier.toString(mo);
Class<?> type = field[i].getType();
System.out.println(modiString + " " + type.getName() + " "
+ field[i].getName() + ";");
}
System.out.println();
// 8、获取全部方法【方法数量不唯一,所以是数组】
Method methods[] = class1.getMethods();
for (int i = 0; i < methods.length; i++) {
// 获取方法的权限修饰符
int mo = methods[i].getModifiers();
String modiString = Modifier.toString(mo);
System.out.print(modiString + " ");
// 获取方法返回类型【返回类型只能是一种】
Class<?> returnType = methods[i].getReturnType();
System.out.print(returnType.getName() + " ");
System.out.print(methods[i].getName() + "(");
// 获取方法参数类型【参数数量不唯一,所以是数组】
Class<?> parameterType[] = methods[i].getParameterTypes();
for (int j = 0; j < parameterType.length; j++) {
System.out.print(parameterType[j].getName() + " " + "arg" + j);
if (j < parameterType.length - 1) {
System.out.print(",");
}
}
// 获取方法的异常抛出类型【异常的数量不唯一,所以是数组】
Class<?> exce[] = methods[i].getExceptionTypes();
if (exce.length > 0) {
System.out.print(") throws ");
for (int k = 0; k < exce.length; k++) {
System.out.print(exce[k].getName() + " ");
if (k < exce.length - 1) {
System.out.print(",");
}
}
} else {
System.out.print(")");
}
System.out.println();
}
// 9、使用反射机制调用方法
Class<?> clazz = Class.forName("com.ez.ReflectClass");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// 调用TestReflect类中的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// 10、使用放射机制操作属性
Class<?> clazz1 = Class.forName("com.ez.ReflectClass");
Object obj = clazz1.newInstance();
// 可以直接对 private 的属性赋值
Field field1 = clazz1.getDeclaredField("test");
field1.setAccessible(true);
field1.set(obj, "Java反射机制");
System.out.println(field1.get(obj));
}
}
在这个练习中,我遇到了一个很棘手的问题,并且很难看出问题的。错误异常如下:
at java.lang.Class.newInstance0(Unknown Source)
这是因为我添加了3个有参构造函数,这样就会导致无参构造函数不被默认创建。
但是,在Class类中,
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
这个方法会去寻找无参构造函数,就会跑出这个异常。
解决方案就是:手动添加一个无参构造函数。