能够分析类能力的类称为反射(reflective)。
反射可以用来:
- 运行时分析类的能力。
- 在运行时查看对象。
- 实现通用的数组操作代码。
使用反射的人主要是工具构造者。
5.7.1 Class类
//获取Class的方式。 e.getClass();//第一种方式 String className = "java.util.Random";//第二种方式 Class cl = Class.forName(className); .class //第三种方式
虚拟机为每个类型管理一个Class对象。
//动态创建一个类的实例
e.getClass().newInstance();
//调用默认构造器初始化新创建的对象。
String s = "java.util.Random";
Object m = Class.forName(s).getInstance();
//如果希望创建的类的构造器提供参数:
Class<?> classType = String.class;
Constructor cons = classType.getConstructor(new Class[] {});
Object obj = cons.newInstance(new Object[]{});
Class<?> classType = B.class;
Constructor cons = classType.getConstructor(int.class,String.class);
Object obj = cons.newInstance(999,"一只独立特性的猪");
Field [] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType().getName() + field.getName());
}
System.out.println(obj.toString());
5.7.2捕获异常
异常分为两种类型:未检查异常和已检查异常(编译器将会检查是否提供了处理器)。
java.lang.Throwable
- void printStackTrace()
将Throwable对象和栈的轨迹输出到标准错误流。
5.7.3利用反射分析类的能力
Field | Method | Constructor 这三个类还有一个叫做getModifies的方法,它将返回一个整型数值,用不同的位开关描述public和static这样的修饰符使用状况。
Modifier类的而静态方法:isPublic isPrivate或isFinal。
field.getModifiers();//输出一个整数值 Modifier.toString(field.getModifiers())//输出private public ...
Class类中的getFields getMethod getConstructors 方法都将分别返回类提供的public域 方法和构造器数组,其中包括超类的共有成员。Class类的getDeclareFields getDeclareMethods getDeclaredConstructors方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但是不包括超类的成员。
java.reflect.Modifier 类中包含的都是一些判断。判断类的访问修饰符,接口还是方法。
5.7.4在运行时使用反射分析对象
查看对象域的关键方法是Field类中的get方法。f.get(obj);
Class cl = this.getClass(); Field f = cl.getDeclaredField("name"); Object v = f.get(this);
设置访问域
f.setAccessible(true);
反射机制将会自动地将这个域值打包到对应的对象包装器中。
ObjectAnalyzer将记录已经被访问过的对象。
new ObjectAnalyzer().toString(this);
Class cl = this.getClass(); cl.isPrimitive();//判断是否是原始类型 //确定对应数组类型 getComponentType() //返回 类数组的组件类型的Class。 String[] arr = new String[] {"admin"}; Class arrClass = arr.getClass(); Class componentType = arrClass.getComponentType(); if (componentType != null) { System.out.println("ComponentType = " + componentType.getName()); }else { System.out.println("ComponentType is null"); }
5.7.5 使用反射编写泛型数组代码
Java 数组会记住每个元素的类型,即创建数组时new表达式中使用的元素类型。
Object newArray = Array.newInstance(componentType,newLength);
public static Object copyOf(Object a, int newLength); Class cl = a.getClass(); if(cl.isArray()) return null; Class componentType = c1.getComponrnType(); int length = Array.getLength(a); Object newArray = Array.newInstance(componentType,newLength); System.arraycopy(a,0,newArray,0,Math.min(length,newLength)); return newArray; }
整型数组类型 int[] 可以被转换成Object,但不能转换为对象数组。
5.7.6调用任意方法
Method类中有一个invoke方法,它允许调用包装在当前Method对象中的方法。
Object invoke(Object obj,Object...args); //第一个参数时隐式参数,其余的对象提供了显式参数,对于静态方法,第一个参数可以被忽略,即将它设为null。
例如,用m1代表Person类的getName方法,下面的语句显示如何调用这个方法:
Sring n = (String)m1.invoke(harry);
如果返回类型时基本类型,invoke方法会返回其包装器类型。
invoke的参数和方法必须是Object类型的。这也意味着必须进行多次类型转换。
建议Java开发者不要使用Method对象的回调功能。使用接口进行回调会使得代码的执行速度更快,更易于维护。
Class<?> classType = B.class; Constructor cons = classType.getConstructor(int.class,String.class); Object obj = cons.newInstance(999,"一只独立特性的猪"); Field [] fields = obj.getClass().getDeclaredFields(); Method m1 = obj.getClass().getDeclaredMethod("getName"); System.out.println(m1); System.out.println((String)m1.invoke(obj));
执行结果
public java.lang.String com.example.demo.entity.B.getName() 一只独立特性的猪