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,只作为本人学习用,观看完整版请看以下链接:
链接:https://www.jianshu.com/p/bd8a505ce135(博客借鉴 地址)

以上是关于java反射机制的主要内容,如果未能解决你的问题,请参考以下文章

java 中反射机制和内省机制的区别是啥?

java反射机制

请问java中的反射机制与用法

如何利用java的反射机制动态创建对象

Java反射机制详解

Java反射机制详解