大数据之路week05--day07(序列化、类加载器、反射、动态代理)

遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题

a,什么叫序列化和反序列化
b,作用。为啥要实现这个 Serializable 接口,也就是为啥要序列化
c,serialVersionUID 这个的值到底是在怎么设置的,有什么用。有的是1L,有的是一长串数字,迷惑ing。
我刚刚见到这个关键字 Serializable 的时候,就有如上的这么些问题。

在处理这个问题之前,你要先知道一个问题,这个比较重要。
这个Serializable接口,以及相关的东西,全部都在 Java io 里面的。

序列化和反序列化的概念

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

上面是专业的解释,现在来点通俗的解释。在代码运行的时候,我们可以看到很多的对象(debug过的都造吧),
可以是一个,也可以是一类对象的集合,很多的对象数据,这些数据中,
有些信息我们想让他持久的保存起来,那么这个序列化。
就是把内存里面的这些对象给变成一连串的字节描述的过程。
常见的就是变成文件
我不序列化也可以保存文件啥的呀,有什么影响呢?我也是这么问的。

什么情况下需要序列化

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
当你想用套接字在网络上传送对象的时候;
当你想通过RMI传输对象的时候;
(老实说,上面的几种,我可能就用过个存数据库的)

序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- >流数据

  ObjectOutputStream

反序列化流:把文本文件中的流对象数据或者网络中的流数据还原成对象。流数据 -->对象

  ObjectInputStream

实现方式:

1、创建类对象,实现Serializable接口,这里要注意,可能还需要使用以前写过的数据,不能重新写入,怎么办呢?回想一下原因是因为他们的id值不匹配。每次修改Java文件的时候,class文件的id值就都会发生改变。而读取文件的时候,会和class文件中的id值进行匹配。所以会在这里出错。点击鼠标黄色警告线,产生一个序列化id值,在产生这个值以后,我 1 package com 2

 3 import java.io.Serializable;
 4 
 5 /**
 6 
 7  * 创建时间:2019年12月8日 上午10:37:39
 8 
 9  * 项目名称:practise11_IO流之序列化流
10 
11  * @author WYH
12 
13  * @version 1.0
14 
15  * @since JDK 1.8.0
16 
17  * 文件名称:Person.java
18 
19  * 类说明:
20  * 
21  * public interface Serializable类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。 
22  * 
23  * 
24  * com.wyh.序列化流.Person; local class incompatible: 
25  * stream classdesc serialVersionUID = 6648182538968226975, 
26  *       local class serialVersionUID = -45489707125759941
27 
28  */
29 
30 public class Person implements Serializable {
31     /**
32      * 
33      */
34     private static final long serialVersionUID = 5318313058664051662L;
35     private String name;
36     private int age;
37 //    int age;
38     //如果该成员变量不想被序列化,加transient关键字
39 //    private transient int age;
40     public Person(String name, int age) {
41         super();
42         this.name = name;
43         this.age = age;
44     }
45     public Person() {
46         super();
47         // TODO Auto-generated constructor stub
48     }
49     public String getName() {
50         return name;
51     }
52     public void setName(String name) {
53         this.name = name;
54     }
55     public int getAge() {
56         return age;
57     }
58     public void setAge(int age) {
59         this.age = age;
60     }
61     @Override
62     public String toString() {
63         return "Person [name=" + name + ", age=" + age + "]";
64     }
65     
66     
以后我们如果看到类实现了这个接口,我们就要意识到,该对象可以被写入到文件,也可以在网络上被当作流一样传输。我一个类中可能有很多的成员变量,有些我不想序列化,请问怎么办呢?上面代码其实给出了,使用transient关键字声明不需要序列化的成员变量。

test

 

 1 package com.wyh.序列化流;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 import java.io.ObjectInputStream;
 7 import java.io.ObjectOutputStream;
 8 
 9 /**
10 
11  * 创建时间:2019年12月8日 上午10:36:40
12 
13  * 项目名称:practise11_IO流之序列化流
14 
15  * @author WYH
16 
17  * @version 1.0
18 
19  * @since JDK 1.8.0
20 
21  * 文件名称:ObjectOutputStream.java
22 
23  * 类说明:
24  *         序列化
25  *         反序列化
26 
27  */
28 
29 public class ObjectOutputStreamDemo {
30 
31     public static void main(String[] args) throws IOException, ClassNotFoundException {
32         //因为是针对对象操作的,所以我们要造一个实体类
33         write();
34         read();
35     }
36 
37     private static void read() throws IOException, ClassNotFoundException {
38         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
39         Object obj = ois.readObject();
40         System.out.println(obj);
41         ois.close();
42         
43     }
44 
45     private static void write() throws IOException {
46         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
47         Person p = new Person("李智恩",20);
48         
49         oos.writeObject(p);
50         oos.close();
51         
52     }
53 
54 }

 

 

 

类加载器

类的加载

  当程序要使用某个类的时候,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化散步来实现对这个类进行初始化。

  加载

    就是指将class文件读入内存,并为之创建一个Class对象。

    任何类被使用时系统都会建立一个Class对象。

  连接

    验证 是否有正确的内部结构,并和其他类协调一致

     准备 负责为类的静态成员分配内存,并设置默认的初始化值

     解析 将类的二进制数据中的符号引用替换为直接引用

  初始化 就是我们以前讲过的初始化步骤

类初始化时机

  创建类的实例

  访问类的静态变量,或者为静态变量赋值

  调用类的静态方法

  使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

  初始化某个类的子类

  直接使用java.exe命令来运行某个主类

类加载器

  负责将.class文件加载到内存中,并为之生成对应的Class对象。

  虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

类加载器的组成

  Bootstrap ClassLoader 根类加载器

  Extendsion ClassLoader 扩展类加载器

  System ClassLoader 系统类加载器

类加载器的作用

Bootstrap ClassLoader 根类加载器

  也被称为引导类加载器,负责Java核心类的加载

    比如System,String等。在JDK中JRE的lib目录下rt.jar文件中。

Extendsion ClassLoader 扩展类加载器

  负责JRE扩展目录中jar包的加载。

    在JDK中JRE的lib目录下ext目录中

System ClassLoader 系统类加载器

  负责在JVM启动时加载来自Java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

那么,如何使用累加器产生的.class文件呢?

那就是:反射

  JAVA反射机制时在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法对的功能称之为Java语言的反射机制。

  要想解剖一个类,必须先要获取到该类的字节码文件对象。而加平剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

 

 

 获取class文件对象有三种方式:

A: Object类中的getClass()方法

B: 数据类型的静态属性Class

C: Class类中的静态方法

    注意,要写类的全路径(也就是带包名的全路径),以后看到类似的也是这么写。

代码演示:

Person类:

 1 package com.wyh.itcast01;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午1:45:03
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:Person.java
16 
17  * 类说明:
18 
19  */
20 
21 public class Person {
22     private String name;
23     int age;
24     public String address;
25     
26     public Person(){
27         
28     }
29     
30     private Person(String name){
31         this.name = name;
32     }
33     
34     Person(String name,int age){
35         this.name = name;
36         this.age = age;
37     }
38     
39     public Person(String name,int age,String address){
40         this.name = name;
41         this.age = age;
42         this.address = address;
43     }
44     
45     public void show(){
46         System.out.println("show");
47     }
48     
49     private void method(String s){
50         System.out.println("method"+s);
51     }
52     
53     public String getString(String s,int i){
54         return s+"---"+i;
55     }
56     
57     public void function(){
58         System.out.println("function");
59     }
60 
61     @Override
62     public String toString() {
63         return "Person [name=" + name + ", age=" + age + ", address=" + address
64                 + "]";
65     }
66     
67     
68 
69 }

测试类:

 1 package com.wyh.itcast01;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午1:41:22
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:ReflactDemo.java
16 
17  * 类说明:
18  *  反射获取Class文件对象的三种方式
19 
20  */
21 
22 public class ReflactDemo {
23     public static void main(String[] args) throws ClassNotFoundException {
24         //第一种方式
25         Person p = new Person();
26         Class c = p.getClass();
27         
28         Person p2 = new Person();
29         Class c2 = p2.getClass();
30         System.out.println(p==p2);//false
31         System.out.println(c==c2);//true
32         
33         //第二种方式
34         Class c3 = Person.class;
35         System.out.println(c==c3);//true
36         
37         //第三种方式
38         Class c4 = Class.forName("com.wyh.itcast01.Person");//注意这里写全路径
39         System.out.println(c==c4);//true 说明拿到的是同一个Class文件
40         
41         
42         
43     }
44     
45 
46 }

一般我们到底使用谁呢?

  注意,一般我们自己学习或者练习的时候,任选一种,但是,实际开发过程中,我们选择第三种,因为第三种传的是一个字符串,而不是一个具体的类名,这样我们就可以把这样的字符串配置到配置文件中。

在我们知道怎么获取class字节码文件了之后,我们继续学习怎么获取构造方法,怎么创建对象,怎么获取成员方法并使用,怎么获取成员变量怎么使用?

1、通过反射获取构造方法

public Constructor[] getConstructors() 获取所有的公共的构造方法

public Constructor[] getDeclaredConstructors() 获取所有的构造方法,包括私有,默认

public Constructor<T> getConstructor(Class<?>...parameterTypes) 获取单个构造方法

Person类:

 1 package com.wyh.itcast01;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午1:45:03
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:Person.java
16 
17  * 类说明:
18 
19  */
20 
21 public class Person {
22     private String name;
23     int age;
24     public String address;
25     
26     public Person(){
27         
28     }
29     
30     private Person(String name){
31         this.name = name;
32     }
33     
34     Person(String name,int age){
35         this.name = name;
36         this.age = age;
37     }
38     
39     public Person(String name,int age,String address){
40         this.name = name;
41         this.age = age;
42         this.address = address;
43     }
44     
45     public void show(){
46         System.out.println("show");
47     }
48     
49     private void method(String s){
50         System.out.println("method"+s);
51     }
52     
53     public String getString(String s,int i){
54         return s+"---"+i;
55     }
56     
57     public void function(){
58         System.out.println("function");
59     }
60 
61     @Override
62     public String toString() {
63         return "Person [name=" + name + ", age=" + age + ", address=" + address
64                 + "]";
65     }
66     
67     
68 
69 }

通过反射获取无参构造方法并使用

 1 package com.wyh.itcast02;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 /**
 6 
 7  * 创建时间:2019年12月8日 下午2:29:03
 8 
 9  * 项目名称:practise12_反射
10 
11  * @author WYH
12 
13  * @version 1.0
14 
15  * @since JDK 1.8.0
16 
17  * 文件名称:ReflactDemo2.java
18 
19  * 类说明:'
20  *         通过反射获取无参构造方法并使用
21 
22  */
23 
24 public class ReflactDemo {
25     public static void main(String[] args) throws Exception {
26         //获取Class对象
27         Class c = Class.forName("com.wyh.itcast01.Person");
28         
29         //获取多个构造方法
30 //        getConstructors() 获取所有公共的
31         /*Constructor[] cos = c.getConstructors();
32         for(Constructor c1 : cos){
33             System.out.println(c1);
34         }*/
35         
36         
37         //getDeclaredConstructors() 获取所有的构造方法
38         Constructor[] cos = c.getDeclaredConstructors();
39         for(Constructor c1 : cos){
40             System.out.println(c1);
41         }
42         
43         //获取单个构造方法
44         Constructor c2 = c.getConstructor();
45         System.out.println(c2);
46         
47         //获取实例对象
48         Object obj = c2.newInstance();
49         System.out.println(obj);
50         
51         
52     }
53 
54 }

通过反射获取带参构造方法并使用

 1 package com.wyh.itcast02;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 /**
 6 
 7  * 创建时间:2019年12月8日 下午2:29:03
 8 
 9  * 项目名称:practise12_反射
10 
11  * @author WYH
12 
13  * @version 1.0
14 
15  * @since JDK 1.8.0
16 
17  * 文件名称:ReflactDemo2.java
18 
19  * 类说明:'
20  *         通过反射获取带参构造方法并使用
21 
22  */
23 
24 public class ReflactDemo2 {
25     public static void main(String[] args) throws Exception {
26         //获取class文件
27         Class c = Class.forName("com.wyh.itcast01.Person");
28         //获取带参构造
29         Constructor c1 = c.getConstructor(String.class,int.class,String.class);
30         //利用带参构造创建实例
31         Object obj = c1.newInstance("李智恩",20,"安徽合肥");
32         System.out.println(obj);
33         
34     }
35 
36 }

通过反射获取私有的构造方法并使用

 1 package com.wyh.itcast02;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 /**
 6 
 7  * 创建时间:2019年12月8日 下午2:29:03
 8 
 9  * 项目名称:practise12_反射
10 
11  * @author WYH
12 
13  * @version 1.0
14 
15  * @since JDK 1.8.0
16 
17  * 文件名称:ReflactDemo2.java
18 
19  * 类说明:'
20  *         通过反射获取私有的构造方法并使用
21 
22  */
23 
24 public class ReflactDemo3 {
25     public static void main(String[] args) throws Exception {
26         //获取class文件
27         Class c = Class.forName("com.wyh.itcast01.Person");
28         //获取私有的构造方法
29         Constructor c1 = c.getDeclaredConstructor(String.class);
30         //实例化一个对象出来
31         
32         //Class com.wyh.itcast02.ReflactDemo3 can not access a member of class com.wyh.itcast01.Person with modifiers "private"
33         //设置访问权限
34         c1.setAccessible(true);
35         Object obj = c1.newInstance("王友虎");
36         System.out.println(obj);
37         
38     }
39 
40 }

2、通过反射获取成员变量并使用

 1 package com.wyh.itcast03;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Field;
 5 
 6 /**
 7 
 8  * 创建时间:2019年12月8日 下午3:13:04
 9 
10  * 项目名称:practise12_反射
11 
12  * @author WYH
13 
14  * @version 1.0
15 
16  * @since JDK 1.8.0
17 
18  * 文件名称:ReflactDemo.java
19 
20  * 类说明:
21  *         通过反射获取成员变量并使用
22 
23  */
24 
25 public class ReflactDemo {
26     public static void main(String[] args) throws Exception {
27         //获取class文件
28         Class c = Class.forName("com.wyh.itcast01.Person");
29 
30         //获取所有公共的成员变量
31 //        Field[] fields = c.getFields();
32         
33         //获取所有的成员变量,包括私有的
34         Field[] fields = c.getDeclaredFields();
35         for(Field field : fields ){
36             System.out.println(field);
37         }
38         
39         //获取单个的成员变量
40         Field addressField = c.getField("address");
41         
42         //获取单个的私有成员变量
43         Field nameField = c.getDeclaredField("name");
44         //同样需要进行权限设置
45         nameField.setAccessible(true);
46         
47         //获取单个成员变量(非私有也不是公共的)
48         Field ageField = c.getDeclaredField("age");
49         //同样需要进行权限设置
50         ageField.setAccessible(true);
51         
52         //获取无参构造
53         Constructor c1 = c.getConstructor();
54         //通过无参构造对象创建一个实例
55         Object obj = c1.newInstance();
56         System.out.println("未赋值之前:"+obj);
57         
58         //对获取到的非私有的成员变量进行赋值
59         addressField.set(obj, "中国安徽");
60         System.out.println("赋值了地址:"+obj);
61         
62         //对获取到的私有成员变量进行赋值
63         nameField.set(obj, "王友虎");
64         System.out.println("赋值了姓名:"+obj);
65         
66         //对获取到的非私有的也不是公共的成员变量进行赋值
67         ageField.set(obj, 22);//正确的读法:给obj对象的age进行赋值
68         System.out.println("赋值了年龄:"+obj);
69         
70         
71         
72         
73         
74         
75     }
76 }

3、通过反射获取成员方法并使用

 

 1 package com.wyh.itcast04;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7 
 8  * 创建时间:2019年12月8日 下午4:14:14
 9 
10  * 项目名称:practise12_反射
11 
12  * @author WYH
13 
14  * @version 1.0
15 
16  * @since JDK 1.8.0
17 
18  * 文件名称:ReflactDemo.java
19 
20  * 类说明:
21  *         通过反射获取成员方法并使用
22 
23  */
24 
25 public class ReflactDemo  {
26     public static void main(String[] args) throws Exception {
27         //获取Class对象
28         Class c = Class.forName("com.wyh.itcast01.Person");
29         
30         //获取所有的公共方法(包括父类)
31 //        Method[] methods = c.getMethods();
32         
33         //获取自己的所有方法,包括私有方法
34         Method[] methods = c.getDeclaredMethods();
35         for(Method method : methods){
36             System.out.println(method);
37         }
38         
39         //获取无参构造方法
40         Constructor con = c.getConstructor();
41         //通过获取到的无参构造实例一个对象
42         Object obj = con.newInstance();
43         
44         System.out.println("============");
45         
46         //获单个的方法
47         //show()
48         Method showMethod = c.getMethod("show");//第一个参数是方法名,后面是class对象
49         //调用show方法  invoke(obj, args);
50         System.out.println("调用show方法:");
51         showMethod.invoke(obj);
52         
53         //getString(String,int)
54         Method getStringMethod = c.getMethod("getString", String.class,int.class);
55         System.out.println("调用getString方法:");
56         System.out.println(getStringMethod.invoke(obj, "小虎",22));
57         
58         //method(String)
59         Method methodM = c.getDeclaredMethod("method", String.class);
60         methodM.setAccessible(true);//因为是私有的成员方法,所以同样需要进行设置权限
61         System.out.println("调用method方法:");
62         methodM.invoke(obj, "李智恩");//第一个参数是获取产生的对象名,第二个参数是要传的实际值
63         
64     }
65 
66 }

 

实例1、通过反射读取xml文件,并使用

我们就用class.txt来代替,里面的写法是键值对写法

class.txt

 1 ClassName=com.wyh.Test.Teacher

2 MethodName=love 

 

编写三个类,学生类,老师类,工人类

Student:

 1 package com.wyh.Test;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午5:05:05
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:Student.java
16 
17  * 类说明:
18 
19  */
20 
21 public class Student {
22     public void love(){
23         System.out.println("爱生活,爱Java");
24     }
25 
26 }

teacher:

 1 package com.wyh.Test;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午5:05:42
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:Teacher.java
16 
17  * 类说明:
18 
19  */
20 
21 public class Teacher {
22     public void love(){
23         System.out.println("爱生活,爱李智恩");
24     }
25 
26 
27 }

Worker类:

 1 package com.wyh.Test;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午5:06:00
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:worker.java
16 
17  * 类说明:
18 
19  */
20 
21 public class worker {
22     public void love(){
23         System.out.println("爱生活,爱工作");
24     }
25 
26 
27 }

测试类:

 1 package com.wyh.Test;
 2 
 3 import java.io.FileReader;
 4 import java.lang.reflect.Constructor;
 5 import java.lang.reflect.Method;
 6 import java.util.Properties;
 7 
 8 /**
 9 
10  * 创建时间:2019年12月8日 下午5:06:15
11 
12  * 项目名称:practise12_反射
13 
14  * @author WYH
15 
16  * @version 1.0
17 
18  * @since JDK 1.8.0
19 
20  * 文件名称:test.java
21 
22  * 类说明:
23 
24  */
25 
26 public class test {
27     public static void main(String[] args) throws Exception {
28         Properties prop = new Properties();
29         FileReader fr = new FileReader("class.txt");
30         prop.load(fr);
31         fr.close();
32         
33         String className = prop.getProperty("ClassName");
34         String methodName = prop.getProperty("MethodName");
35         
36         Class c = Class.forName(className);
37         Constructor con = c.getConstructor();
38         Object obj = con.newInstance();
39         
40         Method m = c.getMethod(methodName);
41         m.invoke(obj);
42         
43         
44     }
45 
46 }

实例2、在ArrayList<Integer>中添加字符串数据

在没学习反射之前集合中,如果添加了泛型控制,我们是没有办法进行这个操作的,但是今天看了源码之后,我们发现,这里的泛型只对编译器可见,底层是Object对象添加,所以这里,我们就可以使用反射拿到class文件,进行添加。

 

 1 package com.wyh.Test02;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Method;
 5 import java.util.ArrayList;
 6 
 7 /**
 8 
 9  * 创建时间:2019年12月8日 下午7:11:31
10 
11  * 项目名称:practise12_反射
12 
13  * @author WYH
14 
15  * @version 1.0
16 
17  * @since JDK 1.8.0
18 
19  * 文件名称:ArrayListDemo.java
20 
21  * 类说明:
22  *         在ArrayList<Integer>中添加字符串数据
23 
24  */
25 
26 public class ArrayListDemo {
27     public static void main(String[] args) throws Exception {
28         ArrayList<Integer> arrays = new ArrayList<Integer>();
29 //        arrays.add(e);
30         
31         //获取字节码文件的另一种方式
32         Class c = arrays.getClass();
33         
34         Method m = c.getMethod("add", Object.class);
35         m.invoke(arrays, "Hello");
36         m.invoke(arrays, "world");
37         m.invoke(arrays, "java");
38         System.out.println(arrays);
39         for(Object o : arrays){
40             System.out.println(o);
41         }
42         
43     }
44 
45 }

 

实例3、实现方法:public void setProperty(Object obj,String propertyName,Object value){},以后类可以通过这个方法进行赋值操作

Tool类:

 

 1 package com.wyh.Test03;
 2 
 3 import java.lang.reflect.Field;
 4 
 5 /**
 6 
 7  * 创建时间:2019年12月8日 下午7:51:43
 8 
 9  * 项目名称:practise12_反射
10 
11  * @author WYH
12 
13  * @version 1.0
14 
15  * @since JDK 1.8.0
16 
17  * 文件名称:Tool.java
18 
19  * 类说明:
20  *         实现方法:
21  *         public void setProperty(Object obj,String propertyName,Object value){}
22 
23  */
24 
25 public class Tool {
26     public void setProperty(Object obj,String propertyName,Object value){
27         Class c = null;
28         Field f = null;
29         try{
30             c = obj.getClass();
31             f = c.getDeclaredField(propertyName);
32             f.setAccessible(true);
33             f.set(obj, value);
34         }catch(Exception e){
35             e.printStackTrace();
36         }
37         
38         
39     }
40 
41 }

 

测试类:

 1 package com.wyh.Test03;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午7:55:42
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:ToolTest.java
16 
17  * 类说明:
18 
19  */
20 
21 public class ToolTest {
22     public static void main(String[] args) {
23         Person p = new Person();
24         Tool t = new Tool();
25         t.setProperty(p, "name", "王友虎");
26         t.setProperty(p, "age", 22);
27         System.out.println(p);
28         
29     }
30 }
31 
32 class Person{
33     private String name;
34     int age;
35     @Override
36     public String toString() {
37         return "Person [name=" + name + ", age=" + age + "]";
38     }
39     
40 }

 

动态代理

  代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。

    举例:春季回家买票让人去买

  动态代理:在程序运行过程中产生的这个对象

    而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理。

 

 

 

 

 

 例子实现:有个UserDao的接口,有增删查改的方法,UserDaoImpl实现了这四个方法,但是我们需要在这个四个方法上添加权限检查和日志打印怎么办?如果我现在又增添了一个实体类,每个方法上也是需要这两个方法怎么办?

动态代理(实现InvocationHandler 接口并且重写public Object invoke(Object proxy, Method method, Object[] args){}方法)

UserDao:

 

 1 package com.wyh.动态代理;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午8:06:12
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:UserDao.java
16 
17  * 类说明:
18 
19  */
20 
21 public interface UserDao {
22     public abstract void add();
23     public abstract void delete();
24     public abstract void update();
25     public abstract void find();
26 
27 }

 

UserDaoImpl:

 

 1 package com.wyh.动态代理;
 2 
 3 /**
 4 
 5  * 创建时间:2019年12月8日 下午8:07:44
 6 
 7  * 项目名称:practise12_反射
 8 
 9  * @author WYH
10 
11  * @version 1.0
12 
13  * @since JDK 1.8.0
14 
15  * 文件名称:UserDaoImpl.java
16 
17  * 类说明:
18 
19  */
20 
21 public class UserDaoImpl implements UserDao {
22 
23     @Override
24     public void add() {
25         System.out.println("添加用户");
26         
27     }
28 
29     @Override
30     public void delete() {
31         System.out.println("删除用户");
32         
33     }
34 
35     @Override
36     public void update() {
37         System.out.println("更新用户");
38         
39     }
40 
41     @Override
42     public void find() {
43         System.out.println("查询用户");
44         
45     }
46 
47 }

 

自定义代理类,实现接口并重写方法:

 1 package com.wyh.动态代理;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7 
 8  * 创建时间:2019年12月8日 下午10:46:29
 9 
10  * 项目名称:practise12_反射
11 
12  * @author WYH
13 
14  * @version 1.0
15 
16  * @since JDK 1.8.0
17 
18  * 文件名称:MyInvocationHandler.java
19 
20  * 类说明:
21  *         创建一个代理类
22 
23  */
24 
25 public class MyInvocationHandler implements InvocationHandler {
26     private Object target;
27     
28     public MyInvocationHandler(Object target) {
29         this.target = target;
30     }
31      
32     @Override
33     public Object invoke(Object proxy, Method method, Object[] args)
34             throws Throwable {
35         System.out.println("权限校验。。。");
36         Thread.sleep(1000);
37         Object result = method.invoke(target, args);
38         System.out.println("日志记录。。。");
39         return result;
40     }
41 
42 }

主题类:

Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), h);

 

 1 package com.wyh.动态代理;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 /**
 6  * 
 7  * 创建时间:2019年12月8日 下午10:44:59
 8  * 
 9  * 项目名称:practise12_反射
10  * 
11  * @author WYH
12  * 
13  * @version 1.0
14  * 
15  * @since JDK 1.8.0
16  * 
17  *        文件名称:Test.java
18  * 
19  *        类说明:
20  */
21 
22 public class Test {
23     public static void main(String[] args) {
24         UserDao user = new UserDaoImpl();
25         user.add();
26         user.delete();
27         user.update();
28         user.find();
29 
30         System.out.println("--------------");
31 
32         MyInvocationHandler handler = new MyInvocationHandler(user);
33         UserDao proxy = (UserDao) Proxy.newProxyInstance(user.getClass()
34                 .getClassLoader(), user.getClass().getInterfaces(), handler);//返回的是Object对象,强转成我们需要的对象类型
35         
36         proxy.add();
37         proxy.delete();
38         proxy.update();
39         proxy.find();
40 
41     }
42 
43 }
posted @ 2019-12-09 00:27  Xiaohu_BigData  阅读(285)  评论(0编辑  收藏  举报