java反射技术
在很多的Web框架中不论是spring,struts等都使用了反射技术,那发射是什么呢?反射本身并不是一个新概念,尽管计算机科学赋予了反射概念新的含义。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
因此反射其实就是加载并解析出类的各种属性和行为来,比如在各种框架中,我们配置好各种配置文件后,交给框架加载并执行我们的类。
java的反射包java.lang.reflect是jdk提供的反射机制API,常用到的类并不多,主要包括以下类:
1).Constructor 类:用来描述一个类的构造方法
2).Field 类:用来描述一个类的成员变量
3).Method 类:用来描述一个类的方法.
4).Modifer 类:用来描述类内各元素的修饰符
5).Array:用来对数组进行操作.
我们可以通过反射API 来在程序运行过程中取得任何一个已知名称的类的内部信息,包括类的修饰符(public,static 等),基类(超类,父类),实现的接口,字段和方法等信息,并可以可以根据字节码信息来创建该类的实例对象,改变对象的字段内容和调用对象方法。
首先不得不讲一讲Class类 ,该类表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和 double
)和关键字 void
也表示为 Class
对象。Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的。
Class类的forName()方法,可以显示加载类。使用如下:
Class clazz = Class.forName("com.demo.reflectionDemo.Person");
Class clazz2 = Person.class;
获得了类的实例,我们就可以通过反射API得到类的各种属性方法了。就像你已经得到了一个类之后,要使用该类的什么属性,你可以通过反射API来解剖出类的什么属性。
1.获得构造函数
使用Constructor类来解剖类的构造函数,使用Class的如下方法获得构造函数:
Constructor[] getDeclaredConstructors():返回已加载类声明的所有的构造方法的Constructor 对象数组。
Constructor getDeclaredConstructor(Class[] paramTypes):返回已加载类声明的指定构造方法的Constructor 对象,paramTypes 指定了参数类型。
Constructor[] getConstructors():返回已加载类声明的所有的public 类型的构造方法的Constructor 对象数组。
Constructor getConstructor(Class[] paramTypes): 返回已加载类声明的指定的public 类型的构造方法的Constructor 对象,paramTypes 指定了参数类型。
构造实例如下:
Constructor c = clazz.getConstructor(null); // public person()
Constructor c = clazz1.getConstructor(String.class); // public person(String name);
Constructor c = clazz2.getConstructor(String.class,String.class); //public person(String name,String password);
Constructor c = clazz3.getDeclaredConstructor(List.class); //private person(List name);
然后便可以通过构造函数直接构造出一个类的实例来, c.newInstance(), 根据参数的多少有无来的情况来使用参数。如果是私有的属性,可通过方法 c.setAccessible(true) 来打开属性。
2.获得类的方法
反射API提供了Method类,还有如下方法:
Method[] getDeclaredMethods():返回已加载类声明的所有方法的Method 对 象数组,不包括从父类继承的方法
Method getDeclaredMethod(String name,Class[] paramTypes): 返回已加载 类声明的所有方法的Method 对象,不包括从父类继承的方法,参数name 指定方 法的名称,参数paramTypes 指定方法的参数类型
Method[] getMethods():返回已加载类声明的所有方法的Method 对象数组,包 括从父类继承的方法
Method getMethod(String name,Class[] paramTypes): 返回已加载类声明的 所有方法的Method 对象,包括从父类继承的方法,参数name 指定方法的名称,参 数paramTypes 指定方法的参数类型.
使用如下:
Method method = clasz.getMethod("print", null); //public void print();
Method method = clasz.getMethod("validation",String.class,int.class); //public void validation(String name,int id);
Method method = clasz.getMethod("getOrder",String.class,int[].class); // public void getOrder(String name,int[] number);
Method method = clasz.getDeclaredMethod("copyTo",InputStream.class); //private void copyTo(InputStream in);
通过使用invoke方法来调用该方法,method.invoke(), method.invoke(obj,"jack",1)等等,同样如果是不可访问的方法,则可以通过method.setAccessible(true)打开访问权限。如果是静态方法,则其他相同,在调用的时候将object置为null,因为静态方法调用不需要对象。
如果是反射main函数的话,因为main函数的参数是public static void main(String[]args),在invoke的时候需要 method.invoke(null,(Object)new String{"param1","param2","param3"}才是正确的。
3.获取方法的属性域Field
Field[] getDeclaredFields():返回已加载类声明的所有成员变量的Field 对象数 组,不包括从父类继承的成员变量
Field getDeclaredField(String name): 返回已加载类声明的所有成员变量的 Field 对象,不包括从父类继承的成员变量,参数name 指定成员变量的名称
Field[] getFields():返回已加载类声明的所有public 型的成员变量的Field 对象 数组,包括从父类继承的成员变量
Field getField(String name):返回已加载类声明的所有成员变量的Field 对象, 包括从父类继承的成员变量,参数name 指定成员变量的名称
使用实例如下:
Field f = claz.getField("name");
Class type = f.getType();
if(type.equals(String.class)){
String svalue = (String)value; System.out.println(svalue);
}
f.set(p, "xxxxxxxxx");
此外,还可以获取类的其他信息:
开发框架是,经常需要使用java对象的属性来封装程序的数据,每次都使用发射技术完成此类的操作过于麻烦,所有sun公司开发了一套API,专门用于操作java对象的属性。内省访问javabean属性的两种方式:
1)通过PropertyDescriptor 类操作Bean的属性。
2)通过Introspector类获得Bean对象的BeanInfo,然后BeanInfo来获取属性的描述器,通过这个属性的描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
使用Introspector类分析 bean 的类和超类,寻找显式或隐式信息,使用这些信息构建一个全面描述目标 bean 的 BeanInfo 对象。使用实例如下:
BeanInfo info = Introspector.getBeanInfo(Person.class, Object.class); //获取person自己的属性
for (PropertyDescriptor pd : pds) {
System.out.println(pd.getName());
}
下列是获取指定属性:
PropertyDescriptor pds = new PropertyDescriptor("age", Person.class);
method.invoke(p, 12);
method = pds.getReadMethod();
System.out.println(method.invoke(p, null));
获取当前操作的属性类型:
PropertyDescriptor pds = new PropertyDescriptor("password", Person.class);
System.out.println(pds.getPropertyType());
如果通过类型操作Bean的属性有些麻烦,apache有一个BeanUtils包,可以用来专门操作Bean的属性,关于BeanUtils的使用参看网上资料。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步