反射技术
一、反射概述
1. 反射机制
* 指的是可以于运行时加载、探知、使用编译期间完全未知的类。
* 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个 已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对 象,都能够调用它的任意一个方法和属性;
* 加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。
2. Class类介绍
* java.lang.Class类十分特殊,用来表示java中类型 (class/interface/enum/annotation/primitive type/void)本 身。
* Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象。
* 当一个class被加载,或当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象。
* Class类是Reflection的根源。针对任何您想动态加载、运行的类,唯有先获得相应的Class 对象
Class的三种获取方式
* a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件
* b:静态属性class,锁对象
* c:Class类中静态方法forName(),读取配置文件
二、通过反射获取带参构造方法并使用
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Demo3_Constructor {
/**
* Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数,
* 就不能这样创建了,可以调用Class类的getConstructor
* (String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance
* ("张三",20)方法创建对象
* @throws Exception
*/ public static void main( String [] args) throws Exception {
Class clazz = Class.forName( "cn.wj.bean.Person" );
//Person p = (Person) clazz.newInstance(); 通过无参构造创建对象 //System.out.println(p); Constructor c = clazz.getConstructor( String . class , int . class ); //获取有参构造 Person p = (Person) c.newInstance( "张三" , 23 ); //通过有参构造创建对象 System.out.println(p);
}
}
三、通过反射获取成员变量并使用
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Demo4_Field {
/**
* Class.getField(String)方法可以获取类中的指定字段(可见的),
* 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值,
* 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
* @throws Exception
*/ public static void main( String [] args) throws Exception {
Class clazz = Class.forName( "cn.wj.bean.Person" );
Constructor c = clazz.getConstructor( String . class , int . class ); //获取有参构造 Person p = (Person) c.newInstance( "张三" , 23 ); //通过有参构造创建对象
//Field f = clazz.getField("name"); //获取姓名字段 //f.set(p, "李四"); //修改姓名的值 Field f = clazz.getDeclaredField( "name" ); //暴力反射获取字段 f.setAccessible(true); //去除私有权限 f.set(p, "李四" );
System.out.println(p);
}
}
四、通过反射获取方法并使用
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Demo5_Method {
/**
* Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String,
* Class...)方法可以获取类中的指定方法,调用invoke(Object,
* Object...)可以调用该方法,Class.getMethod("eat") invoke(obj)
* Class.getMethod("eat",int.class) invoke(obj,10)
* @throws Exception
*/ public static void main( String [] args) throws Exception {
Class clazz = Class.forName( "com.heima.bean.Person" );
Constructor c = clazz.getConstructor( String . class , int . class ); //获取有参构造 Person p = (Person) c.newInstance( "张三" , 23 ); //通过有参构造创建对象
Method m = clazz.getMethod( "eat" ); //获取eat方法 m.invoke(p);
Method m2 = clazz.getMethod( "eat" , int . class ); //获取有参的eat方法 m2.invoke(p, 10 );
}
}
五、动态代理的概述和实现
1,概述
1)代理:本来应该自己做的事,请了别人来做,被请的人就是代理对象
2)动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代 理其实就是通过反射来生成一个代理
2,实现
* 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动 态代理对象。
* JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 最终会调用InvocationHandler的方法
* InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
MyInvocationHandler:
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this .target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println( "权限校验" );
method.invoke(target, args); //执行被代理target对象的方法 System.out.println( "日志记录" );
return null;
}
}
Test类:
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test {
/**
* @param args
*/ public static void main( String [] args) {
StudentImp si = new StudentImp();
si.login();
si.submit();
System.out.println( "-------------------------------" );
MyInvocationHandler m = new MyInvocationHandler(si);
Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);
s.login();
s.submit();
}
}