一、匿名内部类
匿名内部类一般作为方法的参数,这个方法的形参为接口,而实参为匿名内部类(可以理解为接口的对象)并且重写了接口中的方法。
例如:
定义了一个接口Star:
类型为Star的引用数据类型作为方法show()的参数,在调用方法show()是传递一个匿名的Star对象且重写了其中的dance方法,执行结果就是执行重写的dance()的内容:
二、invoke方法
invoke可以理解为对象方法的另一种调用形式。先通过反射机制获取到类的方法并赋给Method对象,再调用Method对象的invoke()方法,invoke()方法的参数指定类的对象名称,实现调用对象的方法的功能。
当调用的方法没有参数时invoke的参数为一个(参数为对象名称),当调用的方法有一个参数时invoke的参数有两个(第一个是对象名称,第二个是方法实行的实参)。
例如:
定义了一个类BigStar:
使用反射机制获取了BigStar的Class对象,并通过getMethod()获取了sing()方法为methodSing,methodSing.invoke()的作用是调用bigStar对象的sing()方法且方法的参数为"好运来":
执行结果如下:
三、动态代理(要先学反射机制不然看不懂)
动态代理的特点是可以无侵入式的给代码增加额外的功能。一般是通过“自定义的代理类”来管理“指定类”(被代理类)的方法的执行,这里的“管理方法的执行”实质是在方法执行前添加一些代码,表现为方法执行的功能增加了。
java.lang.reflect.Proxy类提供了为对象产生代理对象的方法:
补充:
参数一说明:创建的代理类的字节码文件是通过类加载器(ClassLoader)加载到内存中的,书写形式为“创建的代理类名称.class.getClassLoader()”。
参数二说明:写法为"new Class[]{接口1名称.class,接口2名称.class,…}",这样书写之后就可以将所有接口中的方法交给该代理类。
参数三说明:参数三为匿名内部类,形式为:
new InvocationHandler(Object proxy, Method method, Object[] args) throws Throwable{
//自定义内容
}
类InvocationHandler的匿名对象的第一个属性为proxy即为代理对象,第二个属性method为代理要管理的方法,args为传递的要管理的方法调用时传递的参数。当通过代理对象来执行被代理对象的方法时,method就是该方法,args就是该方法的参数。
换一种说法,给“类的方法增加功能”也可以理解为“将一些功能交给代理做,被代理类不管,只做想做的”,就像明星(被代理类)只负责唱歌跳舞,但是场地布置、收费等工作交给工作人员(代理类)来完成。
很晕吧,那就用示例说明:
定义一个接口Star,接口中有两个方法sing()和dance():
类BigStar实现了该接口并重写了两个类,增加了name字段和set,get,构造器方法:
定义的代理类ProxyUtil,该代理类的静态方法createProxy()方法的参数为BigStar对象,返回值为Star接口对象,其中使用了Proxy.newProxyInstance()方法创建了一个代理对象,原本的返回值类型为Object,强转为Star类型并返回,这样就可以通过Proxy.createProxy()方法为其参数对象(这里为BigStar对象bigStar)创建代理(即返回值Star对象star)。Proxy.newProxyInstance()方法的第一个参数了解书写形式即可,第二个参数为执行被代理的接口的字节码,第三个参数的作用是对被代理的接口的方法增加功能,注意代理类是可以对接口中所有的方法增加功能,当通过代理类对象调用被代理类的方法时,该方法就传给invoke()方法里的method,代理类对象调用被代理类的方法时的参数传给args。会发现这里的invoke()方法有返回值,实际上是method.invoke()的返回值,也就是代理类对象调用被代理类的方法的返回值(后面说明):
测试如下,通过ProxyUtil.createProxy方法创建了被代理类BigStar的对象bigStar的代理对象proxy(类型为Star),当调用proxy.dance()方法时,Proxy.new ProxyInstance()中的new InvoactionHandler(){}创建的匿名类会发挥作用,将要执行被代理对象bigStar的dance()方法,并在执行之前添加一些操作,先通过判断得出执行的是被代理对象bigStar的dance()方法(上面的if-else语句),然后执行“System.out.println(“准备场地,收钱”);”,再真正执行dance()方法(通过method.invoke(bigStar,args)实现),增加了功能。
补充:
1.之前提到Proxy.new ProxyInstance()中的new InvoactionHandler(){}创建的匿名对象中重写的invoke()方法的返回值,这里通过例子展示功能:
将代理类执行的方法proxy.sing()的结果返回值就是被代理类结果的返回值。
结语:我承认我的讲述很绕很难理解,能理解的人可以表扬一下自己的理解能力。