一. 什么是JAVA反射
java反射机制是在程序运行状态中,对于任何一个类都可以知道这个类的属性和方法。对于任何一个对象都可以调用它的任意一个方法。Java反射机制运行程序判断分析任何一个类的结构,包括成员方法和变量,并调用任意一个对象的方法。java
二. JAVA反射的实例
在JDK中,主要由如下类来实现Java反射机制,这些类(除了第一个)都位于java.lang.reflect包中编程
Class类:表明一个类,位于java.lang包下。设计模式
Field类:表明类的成员变量(成员变量也称为类的属性)。api
Method类:表明类的方法。数组
Constructor类:表明类的构造方法。app
Class类ide
Class类是用来保存运行时类型信息的类。每一个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。若是没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。通常当某个类的Class对象被载入内存时,它就能够用来建立这个类的全部对象。this
经常使用的获取Class对象的3种方式:url
1.使用Class类的静态方法。例如: spa
Class.forName("java.lang.String");
2.使用类的.class语法。如:
String.class;
3.使用对象的getClass()方法。如:
String str = "aa";
Class<?> classType1 = str.getClass();
Field类
再来看看经过class对象来获取类的属性
private
String strName;
private
int
sum;
public
String strTest;
public
static
void
main(String[] args)
throws
NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ReflectTest rTest=
new
ReflectTest();
Class<?> clsType = ReflectTest.
class
;
//得到当前类和父类中的public类型的全部属性
Field[] fields=clsType.getFields();
for
(Field field:fields)
System.out.println(field);
}
|
经过反射来设置属性值
public
class
ReflectTest {
private
String strName;
private
int
sum;
public
String strTest;
public
void
show(){
System.out.println(strName);
System.out.println(
""
+sum);
System.out.println(strTest);
}
public
static
void
main(String[] args)
throws
NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
ReflectTest rTest=
new
ReflectTest();
Class<?> clsType = ReflectTest.
class
;
//获取三个属性值
Field field1=clsType.getDeclaredField(
"strName"
);
Field field2=clsType.getDeclaredField(
"sum"
);
Field field3=clsType.getField(
"strTest"
);
//反射设置对象的属性值
field1.set(rTest,
"james"
);
field2.set(rTest,
10
);
field3.set(rTest,
"reflect field"
);
rTest.show();
}
}
|
Method类
在获取Class对象后,咱们还能够获取类所对应的方法,这时就要用到咱们的Method类
public
class
ReflectTest {
private
void
fun() {
System.out.println(
"this is fun()"
);
}
private
void
add(
int
a,
int
b) {
System.out.println(
"the sum is: "
+ (a + b) +
" "
);
}
public
static
void
main(String[] args) {
Class<?> clsType = ReflectTest.
class
;
// 返回class对象所对应的类或接口中,所声明的全部方法的数组(包括私有方法)
Method[] methods = clsType.getDeclaredMethods();
// 打印出全部的方法名
for
(Method method : methods) {
System.out.println(method);
}
}
}
|
再来看看怎么反射调用对象的方法
public
class
ReflectTest {
private
void
fun() {
System.out.println(
"this is fun()"
);
}
public
int
add(
int
a,
int
b) {
System.out.println(
"the sum is: "
+ (a + b) +
" "
);
return
a+b;
}
public
static
void
main(String[] args)
throws
NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ReflectTest rTest=
new
ReflectTest();
Class<?> clsType = ReflectTest.
class
;
// 返回对应public类型的方法,第一个参数为方法名,第二个参数为方法的参数列表
Method method=clsType.getMethod(
"add"
,
new
Class<?>[]{
int
.
class
,
int
.
class
});
System.out.println(
""
+method.invoke(rTest,
new
Object[]{
5
,
6
}));
}
}
|
Constructor类
在获取Class对象后,咱们就能够经过它建立类的对象啦。这就地用到咱们的Constructor类啦。有三种建立对象的方式:
1.先得到Class对象,而后经过该Class对象的newInstance()方法直接生成便可:
Class<?> classType = StringBuffer.class;
Object obj = classType.newInstance();
2.固然也能够再得到Class对象后,经过该Class对象得到类的Constructor对象,再经过该Constructor对象的newInstance()方法建立对象:
Class<?> clsType=StringBuffer.class;
// 得到Constructor对象,此处获取一个无参数的构造方法的
Constructor<?> constructor=clsType.getConstructor(new Class<?>[]{});
// 经过Constructor对象的构造方法来生成一个对象
Object obj=constructor.newInstance(new Object[]{});
三、若是构造器带有参数,那就不能有上面两个方法来建立对象了,可以使用下面这一种方式:
Class<?> clsType = StringBuffer.class;
Constructor<?> constructor = clsType.getConstructor(new Class<?>[] { String.class });
Object obj = constructor.newInstance(new Object[] { "hello, classtest" });
三. JAVA反射的原理
Class.forName(classname)的执行过程:
其实是调用了Class类中的 Class.forName(classname, true, currentLoader)方法。参数:name - 所需类的彻底限定名;initialize - 是否必须初始化类;loader - 用于加载类的类加载器。currentLoader则是经过调用ClassLoader.getCallerClassLoader()获取当前类加载器的。类要想使用,必须用类加载器加载,因此须要加载器。反射机制,不是每次都去从新反射,而是提供了cache,每次都会须要类加载器去本身的cache中查找,若是能够查到,则直接返回该类。
java的类加载器,它分为BootStrap Class Loader(引导类加载器),Extensions Class Loader (扩展类加载器),App ClassLoader(或System Class Loader),固然少不了Custom ClassLoader(用户自定义类加载器)。其加载过程当中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只全部ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。
流程图:
类加载器的类加载过程,先检查本身是否已经加载过该类,若是加载过,则直接返回该类,若没有则调用父类的loadClass方法,若是父类中没有,则执行findClass方法去尝试加载此类,也就是咱们一般所理解的片面的"反射"了。这个过程主要经过ClassLoader.defineClass方法来完成。defineClass 方法将一个字节数组转换为 Class 类的实例(任何类的对象都是Class类的对象)。这种新定义的类的实例须要使用 Class.newInstance 来建立,而不能使用new来实例化。
在运行期间,若是咱们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。若是没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就能够用它来产生该类型的全部对象。
四. JAVA反射的应用-动态代理
说动态代理以前,必须先讲讲代理的设计模式。代理模式为其余对象提供一种代理以控制对这个对象的访问。在某些状况下,一个客户不想或者不能直接引用另外一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用。代理模式的有三个角色定义:
这就须要使用咱们的动态代理了。
动态代理(Dynamic Proxy)在系统运行时动态建立代理类,可让系统可以根据实际须要来动态建立代理类,让同一个代理类可以代理多个不一样的真实主题类。动态代理是一种较为高级的代理模式,它在事务管理、AOP(Aspect-OrientedProgramming,面向方面编程)等领域都发挥了重要的做用。Java语言提供了对动态代理的支持,在Java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler接口、另外一个则是 Proxy类。Proxy这个类的做用就是用来动态建立一个代理对象,一般使用newProxyInstance 方法建立代理对象。Proxy代理类动态建立代理对象都须要关联到一个InvocationHandler接口,当咱们经过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke方法来进行调用。
动态代理的步骤
(1).建立一个实现接口InvocationHandler的类,它必须实现invoke方法
(2).建立被代理的类以及接口
(3).经过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 建立一个代理
(4).经过代理调用方法
类图
1
)抽象接口
public
interface
Subject
{
public
void
doSomething(String str);
}
2
)真实对象
public
class
RealSubject
implements
Subject
{
@Override
public
void
doSomething(String str)
{
// TODO Auto-generated method stub
System.out.println(
"do something: "
+ str);
}
}
3
)动态代理Handler类
public
class
MyInvocationHandler
implements
InvocationHandler
{
//被代理的对象
private
Object target=
null
;
public
MyInvocationHandler(Object obj)
{
this
.target=obj;
}
@Override
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable
{
// TODO Auto-generated method stub
return
method.invoke(target, args);
}
}
4
)场景类Client
public
class
Client
{
public
static
void
main(String[] args)
{
//real object
Subject subject=
new
RealSubject();
//handler
InvocationHandler handler=
new
MyInvocationHandler(subject);
//得到代理proxy
Subject proxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
System.out.println(proxy.getClass().getName());
proxy.doSomething(
"yes"
);
}
}
|