Java反射

来源:互联网 发布:彩票源码系统php 编辑:程序博客网 时间:2024/05/22 03:30


反射(reflective)是指能够分析类的能力的程序。

    反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操作Java代码的程序。


    程序运行期间,Java运行时系统始终未所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时信息选择相应的方法执行。


概念叙述


    Class 反射对象描述类的语义结构,可以从Class对象中获取构造函数、成员变量、方法等元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类定义在java.reflect包中,包含Constructor,Method 和 Field。

  • Constructor类的构造函数反射类,通过Class#getConstructors() 方法可以获得类的所有构造函数反射对象数组。在JDK 5.0中,还可以通过getConstructor(Class ...parameterTypes) 获取拥有特定入参的构造函数反射对象。Constructor的一个主要方法是newInstance(Object[] initargs),通过该方法可以创建一个对象类的示例,相当于使用了new关键字。
  • Method类方法的反射类,通过Class#getDeclaredMethods() 方法可以获取类的所有方法反射类对象数组Method[]。在JDK5.0中可以通过 getDeclaredMethod(String name, Class ... parameterTypes)获取特定签名的方法,name为方法名;Class ... 为方法入参类型列表。Method 最主要的方法是invoke(Object obj, Object[] args),obj 标示操作的目标对象,args 为方法入参。此外,Method 方法还有很多用于获取类方法更多信息的方法:Class getReturnType() 获取方法的返回值类型;Class[] getParameterTypes() 获取方法的入参类型数组;Class getExceptionTypes() 获取方法的异常类型数组。
  • Field类的成员变量的反射类,通过Class#getDeclaredFields() 方法可以获取类的成员变量反射对象数组。通过Class#getDeclaredField(String name) 则可获取某个特定名称的成员变量反射对象。Field 类最主要的方法是set(Object obj, Object value) obj 标示操作的目标对象,通过value为目标对象的成员变量设置值。如果成员变量为基础类型,用户可以使用Field 类中提供的带类型名的值设置方法,如setBoolean(Object obj, boolean value)、setInt(Object obj, int value) 等。


代码示例


       部分反射功能在上一篇博文 证明接口interface中的方法访问权限为public 已经做过示例,这里就不再做叙述,这里只讲没有讲到的部分,不了解的朋友,可以先查看上一篇博文。


package com.zhangqi.reflect;public class Car {private String id;private String name;private int maxSpeed;public Car() {};public Car(String id, String name, int maxSpeed) {this.id = id;this.name = name;this.maxSpeed = maxSpeed;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getMaxSpeed() {return maxSpeed;}public void setMaxSpeed(int maxSpeed) {this.maxSpeed = maxSpeed;}// 重写toString方法,输出可读的对象属性数据public String toString() {return "id=" + this.id + ",name=" + this.name + ",maxSpeed=" + this.maxSpeed;}}

测试代码

package com.zhangqi.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class CarReflect {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {Class<?> clazz = Class.forName("com.zhangqi.reflect.Car");// 获取构造函数数组Constructor<?>[] cons = clazz.getConstructors();System.out.println("分割线-- 下面的为构造函数--");// 遍历构造函数数组for (Constructor<?> con : cons) {System.out.println(con);}System.out.println("分割线-- 下面为有参的构造函数--");// 获取指定参数类型的构造方法Constructor<?> conInArgs = clazz.getConstructor(String.class, String.class, int.class);System.out.println(conInArgs);// 调用newInstance 方法构造对象Car car1 = (Car) conInArgs.newInstance("001", "Audi", 210);System.out.println("分割线-- 下面打印car1 对象");System.out.println(car1);// 获取无参的构造方法Constructor<?> conNoArgs = clazz.getConstructor((Class<?>[])null);Car car2 = (Car) conNoArgs.newInstance((Object[])null);// 获取特定签名的方法// 依次获取setId方法、setName方法、setMaxSpeed方法Method setId = clazz.getDeclaredMethod("setId", String.class);System.out.println("分割线-- 下面输出的是setId方法");System.out.println(setId);Method setName = clazz.getDeclaredMethod("setName", String.class);Method setMaxSpeed = clazz.getDeclaredMethod("setMaxSpeed", int.class);// 通过调用invoke方法,给car2 赋属性值setId.invoke(car2, "002");setName.invoke(car2, "Volvo");setMaxSpeed.invoke(car2, 240);System.out.println("分割线 -- 下面打印通过方法赋值后的car2对象");System.out.println(car2);// 获取getId方法Method getId = clazz.getDeclaredMethod("getId", (Class<?>[])null);System.out.println("分割线 -- 下面输出getId方法的返回值类型");// 获取方法的返回值类型System.out.println(getId.getReturnType());System.out.println("分割线-- 下面输出有参构造函数的参数类型");// 获取方法的入参类型数组Class<?>[] parameterTypes = conInArgs.getParameterTypes();for (Class<?> cla : parameterTypes) {System.out.println(cla);}System.out.println("分割线-- 下面输出成员变量id");// 获取某个特定名称的成员变量反射对象Field id = clazz.getDeclaredField("id");System.out.println(id);id.setAccessible(true);// Exception in thread "main" java.lang.IllegalAccessException: Class com.zhangqi.reflect.CarReflect can not access a member of class com.zhangqi.reflect.Car with modifiers "private"id.set(car2, "id002");System.out.println("分割线-- 下面输出通过成员变量赋值方式修改过的对象");System.out.println(car2);}}

输出结果

分割线-- 下面的为构造函数--public com.zhangqi.reflect.Car()public com.zhangqi.reflect.Car(java.lang.String,java.lang.String,int)分割线-- 下面为有参的构造函数--public com.zhangqi.reflect.Car(java.lang.String,java.lang.String,int)分割线-- 下面打印car1 对象id=001,name=Audi,maxSpeed=210分割线-- 下面输出的是setId方法public void com.zhangqi.reflect.Car.setId(java.lang.String)分割线 -- 下面打印通过方法赋值后的car2对象id=002,name=Volvo,maxSpeed=240分割线 -- 下面输出getId方法的返回值类型class java.lang.String分割线-- 下面输出有参构造函数的参数类型class java.lang.Stringclass java.lang.Stringint分割线-- 下面输出成员变量idprivate java.lang.String com.zhangqi.reflect.Car.id分割线-- 下面输出通过成员变量赋值方式修改过的对象id=id002,name=Volvo,maxSpeed=240


代码讲解


Car car1 = (Car) conInArgs.newInstance("001", "Audi", 210);
构造一个Car 对象出来,这里使用newInstance 方法,相当于new 关键字,同时传递相应入参进去。


// 获取方法的入参类型数组Class<?>[] parameterTypes = conInArgs.getParameterTypes();for (Class<?> cla : parameterTypes) {System.out.println(cla);}

这里的输出结果中

class java.lang.Stringclass java.lang.Stringint
前面两个String 对应的是id 和 name的类型,最后的int 是基础类型,所以是单的int


id.setAccessible(true);id.set(car2, "id002");
这里必须要id.setAccessible(true); 因为id为private类型,必须先将其设置为可访问,否则抛出异常

Exception in thread "main" java.lang.IllegalAccessException: Class com.zhangqi.reflect.CarReflect can not access a member of class com.zhangqi.reflect.Car with modifiers "private"



1 0