反射,动态代理随笔

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射,动态代理随笔相关的知识,希望对你有一定的参考价值。

反射的基本概述

  • 一个class文件被加载到内存的时候,JVM就会经行解剖,把这个class文件的所有成员全部解剖出来,然后JVM会创建一个Class对象,把这些成员信息全部都封装起来,所谓反射就是指:我们获取到这个Class对象,就相当于获取到了该类的所有成员信息,我们就能操又该类的所有成员.
  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这类的所有属性和方法;
  • 对于任意一个对象,都能够调用它的任意一个方法和属性;
  • 这种动态获取的细心以及动态调用它的任意一个方法和属性;
  • 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
  • 要想解剖一个类,必须要获取到该类的字节码文件对象.

获取Class对象的三种方式

  • 通过Class.forName()方法获取:

       

static Class<?>

   

  

forName(String className)

          返回与带有给定字符串名的类或接口相关联的 Class 对象。

className--完整类名,eg:com.test.Test01

  • 通过类名直接获取Class对象:

    eg: Class clazz=Person.class;

  • 通过对象获取Class对象:

    eg:Class clazz=new Person().getClass();

  • 写程序的阶段

     

    技术分享

    • 三种方式

Object类的getClass(类的完整类名)方法

读取配置文件,判断两个对象是否是同一个字节码文件

静态属性class(锁对象)

当作静态方法的锁对象

Class类中静态方法forName()

读取配置文件, 判断是否是同一个字节码对象

   

  • 代码案例

    ?

    1 ? package com.heima.reflect;                

    2                  import com.heima.bean.Person;

    3                 

    4                  public class Demo1_Reflect {

    5                 

    6                          /**

    7                           * @param args

    8                           * @throws ClassNotFoundException

    9                           */

    10                          public static void main(String[] args) throws ClassNotFoundException {

    11                                  Class clazz1 = Class.forName("");

    12                                  // 接口 a = 实现类的对象 a.方法

    13                                  //方式一

    14                                  Class clazz2 = Person.class;

    15                                  //方式二

    16                                  Person p = new Person();

    17                                  Class clazz3 = p.getClass();

    18                                  //方式三

    19                                  System.out.println(clazz1 == clazz2);

    20                                  System.out.println(clazz2 == clazz3);

    21                          }

    22                 

  1.                  }
  • Class.forName()读取配置文件_代码示例

    1 ?package com.heima.reflect;

    2

    3 import java.io.BufferedReader;

    4 import java.io.FileReader;

    5

    6 public class Demo2_Reflect {

    7

    8         /**

    9          * * 榨汁机(Juicer)榨汁的案例

    10          * 分别有水果(Fruit)苹果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)

    11          * @throws IOException

    12          */

    13         public static void main(String[] args) throws Exception {

    14                 Juicer j = new Juicer();                                                                        //创建榨汁机

    15                 //j.run(new Apple());

    16                 //j.run(new Orange());

    17                 BufferedReader br = new BufferedReader(new FileReader("config.properties"));//com.heima.reflect.Apple

    18                 Class clazz = Class.forName(br.readLine());                                        //获取该类的字节码文件

    19                 Fruit f = (Fruit) clazz.newInstance();                                                //创建实例对象

    20                 

    21                 j.run(f);

    22         }

    23 }

    24 interface Fruit {

    25         public void squeeze();

    26 }

    27 class Apple implements Fruit {

    28         public void squeeze() {

    29                 System.out.println("榨出一杯苹果汁儿");

    30         }

    31 }

    32

    33 class Orange implements Fruit {

    34         public void squeeze() {

    35                 System.out.println("榨出一杯橘子汁儿");

    36         }

    37 }

    38

    39 class Juicer {

    40         /*public void run(Apple a) {

    41                 a.squeeze();

    42         }

    43         

    44         public void run(Orange o) {

    45                 o.squeeze();

    46         }*/

    47         

    48         public void run(Fruit f) {

    49                 f.squeeze();

    50         }

    51

    52 }

       

       

通过反射获取构造函数_Constructor

  • 成员方法

       

 T

newInstance()

          创建此 Class 对象所表示的类的一个新实例。

 Constructor<T>

getConstructor(Class<?>... parameterTypes)

          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

 Constructor<?>[]

getConstructors()

          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

 Constructor<T>

getDeclaredConstructor(Class<?>... parameterTypes)

          返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。

 Constructor<?>[]

getDeclaredConstructors()

          返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法

   

  • 创建对象_代码示例

    技术分享

       

       

通过反射获取成员变量_Field

  • 成员方法
    • Class类

 Field

getField(String name)

          返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

 Field[]

getFields()

          返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

 Field

getDeclaredField(String name)

          返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

 Field[]

getDeclaredFields()

          返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

   

  • Field类

void 

setAccessible(boolean flag)

          将此对象的 accessible 标志设置为指示的布尔值。

 void 

set(Object obj, Object value)

          将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

   

   

  • 调用方法_代码示例

    技术分享

       

       

通过反射获取成员方法_Method

  • Class类

   

 Method

getMethod(String name, Class<?>... parameterTypes)

          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

 Method[]

getMethods()

          返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

 Method

getDeclaredMethod(String name, Class<?>... parameterTypes)

          返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

 Method[]

getDeclaredMethods()

          返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

   

  • Method类

   

 Object

invoke(Object obj, Object... args)

          对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

  • 案例

    技术分享

   

   

通过反射越过泛型检查

  • 需求:ArrayList的一个对象,在这个集合中添加一个字符串数据,如何实现呢?
  • 泛型只在编译期有效,在运行期会被擦除掉.
  • 代码示例

    1 ?package com.heima.test;

    2

    3 import java.lang.reflect.Method;

    4 import java.util.ArrayList;

    5

    6 public class Test1 {

    7

    8         /**

    9          * @param args

    10          * ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢?

    11          * 泛型只在编译期有效,在运行期会被擦除掉

    12          * @throws Exception

    13          */

    14         public static void main(String[] args) throws Exception {

    15                 ArrayList<Integer> list = new ArrayList<>();

    16                 list.add(111);

    17                 list.add(222);

    18                 

    19                 Class clazz = Class.forName("java.util.ArrayList");                                //获取字节码对象

    20                 Method m = clazz.getMethod("add", Object.class);                                //获取add方法

    21                 m.invoke(list, "abc");

    22                 

    23                 System.out.println(list);

    24                 

    25         }

    26

    27 }

动态代理的概述和实现

  1. 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
  2. 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象.
  3. 成员方法
    1. proxy类

static Object

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

          返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

 

  1. 实现InvocationHandler接口重写invoke方法

 Object

invoke(Object proxy, Method method, Object[] args)

          在代理实例上处理方法调用并返回结果。

   

  1. 代码案例

 

  1. MyInvocationHandler.java_代码示例

1 ?package com.heima.动态代理;

2

3 import java.lang.reflect.InvocationHandler;

4 import java.lang.reflect.Method;

5

6 public class MyInvocationHandler implements InvocationHandler {

7         private Object target;

8         

9         public MyInvocationHandler(Object target) {

10                 this.target = target;

11         }

12         @Override

13         public Object invoke(Object proxy, Method method, Object[] args)

14                         throws Throwable {

15                 System.out.println("权限校验");

16                 method.invoke(target, args);                                        //执行被代理target对象的方法

17                 System.out.println("日志记录");

18                 return null;

19         }

20

21 }

   

  1. Student.java_代码示例

    1 ?package com.heima.动态代理;

    2

    3 public interface Student {

    4         public void login();

    5         

    6         public void submit();

    7 }

       

    1. StudentImp.java_代码示例

    1 ?package com.heima.动态代理;

    2

    3 public class StudentImp implements Student {

    4

    5         @Override

    6         public void login() {

    7                 System.out.println("登录");

    8         }

    9

    10         @Override

    11         public void submit() {

    12                 System.out.println("提交");

    13         }

       

    1. User.java_代码示例

    1 ?package com.heima.动态代理;

    2

    3 public interface User {

    4         public void add();

    5         

    6         public void delete();

    1. }

       

    1. UserImp.java_代码示例

    1 ?package com.heima.动态代理;

    2

    3 public class UserImp implements User {

    4

    5         @Override

    6         public void add() {

    7                 //System.out.println("权限校验");

    8                 System.out.println("添加功能");

    9                 //System.out.println("日志记录");

    10         }

    11

    12         @Override

    13         public void delete() {

    14                 //System.out.println("权限校验");

    15                 System.out.println("删除功能");

    16                 //System.out.println("日志记录");

    17         }

    18

       

    1. Test.java_代码示例

    1 ?package com.heima.动态代理;

    2

    3 import java.lang.reflect.Proxy;

    4

    5 public class Test {

    6

    7         /**

    8          * @param args

    9          */

    10         public static void main(String[] args) {

    11                 /*UserImp ui = new UserImp();

    12                 ui.add();

    13                 ui.delete();

    14                 

    15                 System.out.println("-------------------------------");*/

    16                 /*

    17                  * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,

    18                  * InvocationHandler h)

    19                  */

    20                 /*MyInvocationHandler m = new MyInvocationHandler(ui);

    21                 User u = (User)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);

    22                 u.add();

    23                 u.delete();*/

    24                 

    25                 StudentImp si = new StudentImp();

    26                 si.login();

    27                 si.submit();                

    28                 System.out.println("-------------------------------");

    29                 MyInvocationHandler m = new MyInvocationHandler(si);

    30                 Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);

    31                 

    32                 s.login();

    33                 s.submit();

    34         }

    35

    36 }

以上是关于反射,动态代理随笔的主要内容,如果未能解决你的问题,请参考以下文章

反射,动态代理随笔

反射,动态代理随笔

类的加载机制和反射——使用反射生成JDK动态代理

(java反射-JDK动态代理)+CGLIB动态代理

跟王老师学反射:动态代理

java深入分析Java反射-动态代理 proxy