反射和动态代理使用的地方非常多。
反射 在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法。
应用 开发通用框架
反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 JavaBean、Filter 等),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。动态代理
在切面编程(AOP)中,需要拦截特定的方法,通常,会选择动态代理方式。这时,就需要反射技术来实现了。注解
注解本身仅仅是起到标记作用,它需要利用反射机制,根据注解标记去调用注解解释器,执行行为。如果没有反射机制,注解并不比注释更有用。可扩展
- 应用程序可以通过使用完全限定名称创建可扩展性对象实例来使用外部的用户定义类。缺点 性能开销
由于反射涉及动态解析的类型,因此无法执行某些 Java 虚拟机优化。因此,反射操作的性能要比非反射操作的性能要差,应该在性能敏感的应用程序中频繁调用的代码段中避免。破坏封装性
反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。内部曝光
由于反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,所以反射的使用可能会导致意想不到的副作用,这可能会导致代码功能失常并可能破坏可移植性。反射代码打破了抽象,因此可能会随着平台的升级而改变行为。使用 获取 Class 使用Class.forName()
静态方法 直接获取 调用Object.getClass()
Type 属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class TestClass { public static void main (String[] args) throws ClassNotFoundException { Class mysql = Class.forName("com.mysql.cj.jdbc.Driver" ); System.out.println(mysql.getCanonicalName()); Class b = boolean .class; System.out.println(b.getCanonicalName()); Set<String> set = new HashSet <>(); Class s = set.getClass(); System.out.println(s.getCanonicalName()); Class f = Float.TYPE; System.out.println(f.getCanonicalName()); } }
判断实例 判断是否为某个类的实例有两种方式:
用 instanceof
关键字 用 Class.isInstance()
方法(它是一个 Native 方法) 1 2 3 4 5 6 7 8 9 10 11 public class InstanceofDemo { public static void main (String[] args) { ArrayList arrayList = new ArrayList (); if (arrayList instanceof List) { System.out.println("ArrayList is List" ); } if (List.class.isInstance(arrayList)) { System.out.println("ArrayList is List" ); } } }
创建实例 用 Class
对象的 newInstance
方法。 用 Constructor
对象的 newInstance
方法。 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class NewInstanceDemo { public static void main (String [] args)throws IllegalAccessException , InstantiationException , NoSuchMethodException , InvocationTargetException { Class <?> c1 = StringBuilder .class ; StringBuilder sb = (StringBuilder ) c1.newInstance (); sb.append ("aaa" ); System .out .println (sb.toString ()); Class <?> c2 = String .class ; Constructor constructor = c2.getConstructor (String .class ); String str2 = (String ) constructor.newInstance ("bbb" ); System .out .println (str2); } }
动态代理 特点:字节码随用随创建,随用随加载 作用:不修改源码的基础上对方法增强 JDK 自带的 proxy 基于接口的动态代理 涉及的类:Proxy JDK 官方提供 如何创建:使用Proxy类中的newProxyInstance方法
要求:被代理类最少实现一个接口
,如果没有使用则不能用 newProxyInstance 方法参数:ClassLoader
:类加载器 用于加载代理对象字节码的,和被代理对象使用相同的类加载器。固定写法Class[]
:字节码数组 用于让代理对象和被代理对象有相同方法。固定写法InvocationHandler
:提供增强代码 让我们写如何处理。一般写一个该接口的实现类,通常情况都是匿名内部类,但不必须 此接口的实现类都是谁用谁写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package com.itheima.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Client { public static void main (String[] args) { final Producer producer = new Producer (); IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler () { public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { Object returnValue = null ; Float money = (Float)args[0 ]; if ("saleProduct" .equals(method.getName())){ returnValue = method.invoke(producer,money*0.8f ); } return returnValue; } }); proxyProducer.saleProduct(1000f ); } }
第三方 cglib 基于子类的动态代理 涉及的类:Enhancer 第三方 cglib 提供 如何创建:使用Enhancer类中的create
方法 create 方法参数:Class
;用于指定被代理对象的字节码Callback
:提供增强代码 我们写如何处理。一般写一个该接口的实现类,通常情况都是匿名内部类,但不必须
此接口的实现类都是谁用谁写 一般写子接口实现类:MethodInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.itheima.cglib;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class Client { public static void main (String[] args) { final Producer producer = new Producer (); Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor () { public Object intercept (Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object returnValue = null ; Float money = (Float)args[0 ]; if ("saleProduct" .equals(method.getName())){ returnValue = method.invoke(producer,money*0.8f ); } return returnValue; } }); cglibProducer.saleProduct(120000f ); } }