java反射机制
Posted 王嘉豪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java反射机制相关的知识,希望对你有一定的参考价值。
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。(官方介绍)
反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
4.在运行时调用任意一个对象的方法、与方法的参数(Java8新增)
比如ide可以在.之后列出方法和属性,就是反射的作用,最重要的用途是开发框架,根据配置文件去动态的即时的调用各类、方法
反射的基本运用
1.获取class对象:
1)使用class类的forName静态方法,native
public static Class<?> forName(String className)(完整包名)
2)直接获取某对象的class,是一个静态的属性
Class<?> c =XXXX.class;
3)调用某对象的getClass方法
String str =new String(“111”)
Class<?> klass = str.getClass();
评价:第二种方法更好,代码更安全,性能更加好,Class是类的一个属性,不是方法所以消耗资源低。
2.判断是否是某个类的实例 用isInstance(Object obj)方法,此为native
public native boolean isInstance(Object obj);
3.创建实例
先通过class对象获取指定对象的constructor对象
//获取String对应的class对象
Class<?> c=String.class;
//在构造器里加入一个参数为String类型的参数,这个与下面的实例化对象相对应,如果没有参数那么下面也不需要参数
Constructor constructor = c.getConstructor(c)
Object obj = constructor.newInstance(“111”)
可以使用getDeclaredConstructor()获取指定的构造方法,参数为要调用的构造方法的参数
比如要调用String和int型的构造方法可以有两种方法
getDeclaredConstructor(String.class,int.class)
每个Constructor对象都是一个构造方法
//两个参数对象组成数组
getDeclaredConstructor(new Class[]{String.class,int.class})
4.获取方法
1)getDeclaredMethod方法,可以返回类和接口声明的全部方法组成的数组,不包括继承的
2)getMethod方法,返回所有public方法,包括继承的(因为返回的是所有方法,所以需要用一个数组去获取返回的数据,public method[] )
3)getMethod方法,参数里写明具体的想要返回的方法名字 public method getMethod(“xxxxxx”,参数类型.class,参数类型2. class,~~~~)
5.获取构造器信息 使用getConstructor获取构造器,constructor有newInstance方法创建实例,是在class的newInstance方法过时之后的方法
构造方法的实例代码:
Constructor[] conArray = class.getConstructors();
for(constructor c:conArray){}
6.获取成员变量、字段 同获取方法
getFields()
7.调用method的 invoke()方法
invoke(Object obj,参数数据类型)这里的obj是方法所属的对象。这个方法由获取方法的函数的对象来调用。obj的参数是方法所需要的参数
8.利用反射构造数组 reflect下还提供了Array类
Class<?> cols = Class.forName(“java.lang.String”)
Object array = Array.newInstance(cols,25)
Array.set(array,0,”hello”)
Array.set(array,1,”java”)
Array类源码分析:
newarray()方法为native方法,newIstance方法接收一个class<?>与一个数组大小
class类的实例表示当前正在运行中的java类的应用程序的类和接口
setAccessible(boolean)方法可以设置java是否设置权限检查,通过设置为false可以调用私有成员。调用者为函数,成员或者构造器。
反射main方法:
//根据函数名main和参数对象String[].class获取main方法
Method methodMain = class.getMethod(“main”,String[].class)
//第一个参数为对象类型,由于main方法属于static,在类加载之前就已经加载,所以null可以
methodMain.invoke(null,(Object) new String[]{a,b,c});
通过反射配置文件内容:
利用反射和配置文件,可以使应用程序更新时,对源码无须修改
public classDemo {
public static voidmain(String[] args)throwsException{
//通过反射获取Class对象
Class stuClass = Class.forName(getValue("className"));
//获取show方法
Method m = stuClass.getMethod(getValue("methodName"));
//调用show方法
m.invoke(stuClass.getConstructor().newInstance());
}
public staticString getValue(String key)throwsIOException{
//获取配置文件对象,Properties在java里用作作为配置文件的对象
Properties pro =newProperties();
FileReader in =newFileReader("F:/file/pro.txt");
//将流装载到配置文件
pro.load(in);
in.close();
returnpro.getProperty(key);
}
}
pro.txt:
className = cn.fanshe.student
methodName = show
需要升级系统时,不需要改动上面的执行方法的代码,只需要增加新的需要的类与修改配置文件
想要修改student可以修改配置文件pro.txt 然后新建Student2
Java8新增了一个Executable抽象类,派生出Constructor、Method两个子类。可以获取方法的参数,javac编译java文件时,默认不保存形参名。提供了获得参数与参数个数的方法.同时,可以获得参数类型与泛型类型.
反射生成并操作对象(简单的IOC):
1.生成:获取constructor,在调用newInstance。
2.调用方法:获取类的Class,调用getMethod;由对象作为target调用方法。其中创建对象与调用方法的参数可以从配置文件中获取。
3.成员变量:getField()。设置访问权限,通过get与set设定值。
Java的三种代理:
由于原则上不能随意修改别人的代码,所以需要对某一个类进行增强处理时,必须采用代理对象调用目标对象的方式.
静态代理:
代理对象与被代理对象需要实现相同的接口,或者继承相同的父类.
在代理对象中实现接口方法,并传入一个被代理对象的引用,并调用被代理对象的接口方法
缺点在于一旦需要修改接口数量或者方法等,所有代理类与被代理类都需要修改,重用性低.
反射生成JDK动态代理:
reflect包下的Proxy类与InvocationHandler接口,动态为接口生成代理类和代理对象,此时代理对象不需要实现接口。Proxy是所有动态代理的父类,每一个动态代理都有与之相对的InvocationHandler对象。
ClassName instanceName = (ClassName)Proxy.newProxyInstance(ClassName.getClassLoader(),[ ]Class.interface ,InvocationHandlerInstance h)
实现InvocationHandler的类重写invoke(Proxy,method(正在执行的方法),args)方法,之后调用所有方法都会变成调用invoke(),proxy调用时传入,method即代理对象调用的方法,args为代理对象调用方法时传入的参数.
动态代理和AOP:
对不同代码块进行相同的处理,JDK只能为接口创建动态代理,但是为接口创建动态代理是没有意义的,需要为接口的实现类提供动态代理,所以可以认为jdk只能为实现接口的类提供动态代理,而一般类需要通过cglib框架来实现aop.
InvocationHandler的实现类的意义在于规定了动态代理类的行为,invoke()方法是动态代理类,每一次的调用方法.
本文基本复制作者1t3uka,只作为本人学习用,观看完整版请看以下链接:
以上是关于java反射机制的主要内容,如果未能解决你的问题,请参考以下文章