@@ -703,7 +703,15 @@ public class Main {
703703}
704704```
705705
706- 运行上述代码,可以看到,` Integer ` 的父类类型是` Number ` ,` Number ` 的父类是` Object ` ,` Object ` 的父类是` null ` 。除` Object ` 外,其他任何非` interface ` 的` Class ` 都必定存在一个父类类型。
706+ 运行上述代码,可以看到,
707+
708+ ```
709+ class java.lang.Number
710+ class java.lang.Object
711+ null
712+ ```
713+
714+ ` Integer ` 的父类类型是` Number ` ,` Number ` 的父类是` Object ` ,` Object ` 的父类是` null ` 。除` Object ` 外,其他任何非` interface ` 的` Class ` 都必定存在一个父类类型。
707715
708716### 获取interface
709717
@@ -727,6 +735,9 @@ public class Main {
727735运行上述代码可知,` Integer ` 实现的接口有:
728736
729737- java.lang.Comparable
738+
739+ Java14开始还额外有
740+
730741- java.lang.constant.Constable
731742- java.lang.constant.ConstantDesc
732743
@@ -783,3 +794,126 @@ Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋
783794Integer . class. isAssignableFrom(Number . class); // false,因为Number不能赋值给Integer
784795```
785796
797+ ## 动态代理
798+
799+ 我们来比较Java的` class ` 和` interface ` 的区别:
800+
801+ - 可以实例化` class ` (非` abstract ` );
802+ - 不能实例化` interface ` 。
803+
804+ 所有` interface ` 类型的变量总是通过某个实例向上转型并赋值给接口类型变量的:
805+
806+ ``` java
807+ CharSequence cs = new StringBuilder ();
808+ ```
809+
810+ 有没有可能不编写实现类,直接在运行期创建某个` interface ` 的实例呢?
811+
812+ 这是可能的,因为Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个` interface ` 的实例。
813+
814+ 所谓动态代理,是和静态相对应的。我们来看静态代码怎么写:
815+
816+ 定义接口:
817+
818+ ``` java
819+ public interface Hello {
820+ void morning (String name );
821+ }
822+ ```
823+
824+ 编写实现类:
825+
826+ ``` java
827+ public class HelloWorld implements Hello {
828+ public void morning (String name ) {
829+ System . out. println(" Good morning, " + name);
830+ }
831+ }
832+ ```
833+
834+ 创建实例,转型为接口并调用:
835+
836+ ``` java
837+ Hello hello = new HelloWorld ();
838+ hello. morning(" Bob" );
839+ ```
840+
841+ 这种方式就是我们通常编写代码的方式。
842+
843+ 还有一种方式是动态代码,我们仍然先定义了接口` Hello ` ,但是我们并不去编写实现类,而是直接通过JDK提供的一个` Proxy.newProxyInstance() ` 创建了一个` Hello ` 接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
844+
845+ 一个最简单的动态代理实现如下:
846+
847+ ``` java
848+ import java.lang.reflect.InvocationHandler ;
849+ import java.lang.reflect.Method ;
850+ import java.lang.reflect.Proxy ;
851+
852+ public class Main {
853+ public static void main (String [] args ) {
854+ InvocationHandler handler = new InvocationHandler () {
855+ @Override
856+ public Object invoke (Object proxy , Method method , Object [] args ) throws Throwable {
857+ System . out. println(method);
858+ if (method. getName(). equals(" morning" )) {
859+ System . out. println(" Good morning, " + args[0 ]);
860+ }
861+ return null ;
862+ }
863+ };
864+ Hello hello = (Hello ) Proxy . newProxyInstance(
865+ Hello . class. getClassLoader(), // 传入ClassLoader
866+ new Class [] { Hello . class }, // 传入要实现的接口
867+ handler); // 传入处理调用方法的InvocationHandler
868+ hello. morning(" Bob" );
869+ }
870+ }
871+
872+ interface Hello {
873+ void morning (String name );
874+ }
875+ ```
876+
877+ 在运行期动态创建一个` interface ` 实例的方法如下:
878+
879+ 1 . 定义一个` InvocationHandler ` 实例,它负责实现接口的方法调用;
880+
881+ 2 . 通过
882+
883+ ```
884+ Proxy.newProxyInstance()
885+ ```
886+
887+ 创建
888+
889+ ```
890+ interface
891+ ```
892+
893+ 实例,它需要3个参数:
894+
895+ 1 . 使用的` ClassLoader ` ,通常就是接口类的` ClassLoader ` ;
896+ 2 . 需要实现的接口数组,至少需要传入一个接口进去;
897+ 3 . 用来处理接口方法调用的` InvocationHandler ` 实例。
898+
899+ 3 . 将返回的` Object ` 强制转型为接口。
900+
901+ 动态代理实际上是JVM在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法,把上面的动态代理改写为静态实现类大概长这样:
902+
903+ ``` java
904+ public class HelloDynamicProxy implements Hello {
905+ InvocationHandler handler;
906+ public HelloDynamicProxy (InvocationHandler handler ) {
907+ this . handler = handler;
908+ }
909+ public void morning (String name ) {
910+ handler. invoke(
911+ this ,
912+ Hello . class. getMethod(" morning" , String . class),
913+ new Object [] { name }
914+ );
915+ }
916+ }
917+ ```
918+
919+ 其实就是JVM帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码),并不存在可以直接实例化接口的黑魔法。
0 commit comments