参考:廖雪峰——Java 反射
反射,reflection,旨在在程序运行期间拿到对应对象的所有信息,包括 class 类信息,filed 字段,method 方法,generic 泛型,annotation 注解, package 包、parameter 参数等。
简而言之,通过 Class 来获取 class 信息的方法就叫做反射 reflection。

1 Class 类

在Java 中,除了 primitive 原始 int 等基本类外,其它的类型都是 class (包括 interface)。

1.1 获取到 Class

  1. 方式一:直接通过一个 class 的静态变量 class 获取:

    1. Class clazz = String.class;
  2. 方式二:通过实例变量(对象),通过该实例的 getClass 方法获取

    1. String str = "xiaohui";
    2. Class clazz = str.getClass();
  3. 方式三:通过class 的全类名,调用 Class.forName() 方法获取

    1. Class clazz = Class.forName("java.lang.Integer");

    1.2 Class 与 instanceof

    ```java Integer i = new Integer(12);

boolean b1 = i instanceof Integer; // true, i 就是 Integer 类型 boolean b2 = i instanceof Number; // true, i Integer 是 Number 类型的子类

boolean b3 = i.getClass() == Integer.class; // true // 下面编译报错,Error:(155, 35) java: 不可比较的类型: java.lang.Class和java.lang.Class // boolean b4 = i.getClass() == Number.class; // false

  1. 小结:<br />var instanceof ClassName 不仅匹配指定的类型 ClassName, 还匹配指定类型 ClassName 的子类。== 是精确匹配数据类型,不能进行子类比较(与子类比较,不能获取到 true)。
  2. <a name="HAkGm"></a>
  3. ## 1.3 获取 class 信息小例
  4. `Class`类提供了以下几个方法来获取字段:
  5. - Field getField(name):根据字段名获取某个publicfield(包括父类)(只能获取 pulic 修辞的)
  6. - Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)(包括当前类中所有的声明filed 包括 finalstaticstatic final,无论修辞符是 privateprotecteddefaultpublic,通通都能拿取)
  7. - Field[] getFields():获取所有publicfield(包括父类)
  8. - Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
  9. ```java
  10. public static void main(String[] args) {
  11. System.err.println("String[] args && args.getClass() >>>>>>>>>>>>>>>>>>");
  12. Class<? extends String[]> aClass = args.getClass();
  13. System.out.println("getClass:" + aClass.getClass());
  14. System.out.println("getClasses:" + aClass.getClasses());
  15. System.out.println("isAnnotation:" + aClass.isAnnotation());
  16. System.out.println("isPrimitive:" + aClass.isPrimitive());
  17. System.out.println("isInterface:" + aClass.isInterface());
  18. System.out.println("isArray:" + aClass.isArray());
  19. System.out.println("isEnum:" + aClass.isEnum());
  20. System.out.println("isAnonymousClass:" + aClass.isAnonymousClass());
  21. System.out.println("isAssignableFrom(Object.class):" + aClass.isAssignableFrom(Object.class));
  22. System.err.println("String[].class >>>>>>>>>>>>>>>>>>");
  23. Class<String[]> strArr = String[].class;
  24. System.out.println("getClass:" + strArr.getClass());
  25. System.out.println("getClasses:" + strArr.getClasses());
  26. System.out.println("isAnnotation:" + strArr.isAnnotation());
  27. System.out.println("isPrimitive:" + strArr.isPrimitive());
  28. System.out.println("isInterface:" + strArr.isInterface());
  29. System.out.println("isArray:" + strArr.isArray());
  30. System.out.println("isEnum:" + strArr.isEnum());
  31. System.out.println("isAnonymousClass:" + strArr.isAnonymousClass());
  32. System.out.println("isAssignableFrom(Object.class):" + strArr.isAssignableFrom(Object.class));
  33. System.err.println("String.class >>>>>>>>>>>>>>>>>>");
  34. Class<String> str = String.class;
  35. System.out.println("getClass:" + str.getClass());
  36. System.out.println("getClasses:" + str.getClasses());
  37. System.out.println("isAnnotation:" + str.isAnnotation());
  38. System.out.println("isPrimitive:" + str.isPrimitive());
  39. System.out.println("isInterface:" + str.isInterface());
  40. System.out.println("isArray:" + str.isArray());
  41. System.out.println("isEnum:" + str.isEnum());
  42. System.out.println("isAnonymousClass:" + str.isAnonymousClass());
  43. System.out.println("isAssignableFrom(Object.class):" + str.isAssignableFrom(Object.class));
  44. System.err.println("int.class >>>>>>>>>>>>>>>>>>");
  45. Class<Integer> i = int.class;
  46. System.out.println("getClass:" + i.getClass());
  47. System.out.println("getClasses:" + i.getClasses());
  48. System.out.println("isAnnotation:" + i.isAnnotation());
  49. System.out.println("isPrimitive:" + i.isPrimitive());
  50. System.out.println("isInterface:" + i.isInterface());
  51. System.out.println("isArray:" + i.isArray());
  52. System.out.println("isEnum:" + i.isEnum());
  53. System.out.println("isAnonymousClass:" + i.isAnonymousClass());
  54. System.out.println("isAssignableFrom(Object.class):" + i.isAssignableFrom(Object.class));
  55. System.err.println("Integer.class >>>>>>>>>>>>>>>>>>");
  56. Class<Integer> integerClass = Integer.class;
  57. System.out.println("getClass:" + integerClass.getClass());
  58. System.out.println("getClasses:" + integerClass.getClasses());
  59. System.out.println("isAnnotation:" + integerClass.isAnnotation());
  60. System.out.println("isPrimitive:" + integerClass.isPrimitive());
  61. System.out.println("isInterface:" + integerClass.isInterface());
  62. System.out.println("isArray:" + integerClass.isArray());
  63. System.out.println("isEnum:" + integerClass.isEnum());
  64. System.out.println("isAnonymousClass:" + integerClass.isAnonymousClass());
  65. System.out.println("isAssignableFrom(Object.class):" + integerClass.isAssignableFrom(Object.class));
  66. }

运行结果:

  1. Connected to the target VM, address: '127.0.0.1:52610', transport: 'socket'
  2. String[] args && args.getClass() >>>>>>>>>>>>>>>>>>
  3. getClass:class java.lang.Class
  4. getClasses:[Ljava.lang.Class;@42d3bd8b
  5. isAnnotation:false
  6. isPrimitive:false
  7. isInterface:false
  8. isArray:true
  9. isEnum:false
  10. isAnonymousClass:false
  11. isAssignableFrom(Object.class):false
  12. String[].class >>>>>>>>>>>>>>>>>>
  13. getClass:class java.lang.Class
  14. getClasses:[Ljava.lang.Class;@26ba2a48
  15. isAnnotation:false
  16. isPrimitive:false
  17. isInterface:false
  18. isArray:true
  19. isEnum:false
  20. isAnonymousClass:false
  21. isAssignableFrom(Object.class):false
  22. String.class >>>>>>>>>>>>>>>>>>
  23. getClass:class java.lang.Class
  24. getClasses:[Ljava.lang.Class;@5f2050f6
  25. isAnnotation:false
  26. isPrimitive:false
  27. isInterface:false
  28. isArray:false
  29. isEnum:false
  30. isAnonymousClass:false
  31. isAssignableFrom(Object.class):false
  32. int.class >>>>>>>>>>>>>>>>>>
  33. getClass:class java.lang.Class
  34. getClasses:[Ljava.lang.Class;@3b81a1bc
  35. isAnnotation:false
  36. isPrimitive:true
  37. isInterface:false
  38. isArray:false
  39. isEnum:false
  40. isAnonymousClass:false
  41. isAssignableFrom(Object.class):false
  42. Integer.class >>>>>>>>>>>>>>>>>>
  43. getClass:class java.lang.Class
  44. getClasses:[Ljava.lang.Class;@64616ca2
  45. isAnnotation:false
  46. isPrimitive:false
  47. isInterface:false
  48. isArray:false
  49. isEnum:false
  50. isAnonymousClass:false
  51. isAssignableFrom(Object.class):false
  52. Disconnected from the target VM, address: '127.0.0.1:52610', transport: 'socket'
  53. Process finished with exit code 0

基本的测试类:

  1. class SuperClass {
  2. private String superName;
  3. private String superGender;
  4. public String publicName;
  5. private String privateName;
  6. protected String protectedName;
  7. String defaultName;
  8. public String getSuperName() {
  9. return superName;
  10. }
  11. public void setSuperName(String superName) {
  12. this.superName = superName;
  13. }
  14. public String getSuperGender() {
  15. return superGender;
  16. }
  17. public void setSuperGender(String superGender) {
  18. this.superGender = superGender;
  19. }
  20. }
  21. class SubClassA extends SuperClass {
  22. private final String finalStr = "11";
  23. private static final String finalStaticStr = "22";
  24. private static String staticStr = "333";
  25. private String subName;
  26. private String subGender;
  27. public String subPublicName;
  28. private String subPrivateName;
  29. protected String subProtectedName;
  30. String subDefaultName;
  31. public String getSubName() {
  32. return subName;
  33. }
  34. public void setSubName(String subName) {
  35. this.subName = subName;
  36. }
  37. public String getSubGender() {
  38. return subGender;
  39. }
  40. public void setSubGender(String subGender) {
  41. this.subGender = subGender;
  42. }
  43. }

测试:

  1. public static void testFiled(Class clazz) {
  2. System.out.println("分割线: 》》》》》》》》》》》》》》》 start");
  3. System.out.println("clazz.getSimpleName():" + clazz.getSimpleName());
  4. System.out.println("getFields:" + Arrays.asList(clazz.getFields()).stream().map(x -> x.getName()).collect(
  5. Collectors.joining(",")));
  6. System.out.println(
  7. "getDeclaredFields:" + Arrays.asList(clazz.getDeclaredFields()).stream().map(x -> x.getName()).collect(
  8. Collectors.joining(",")));
  9. }
  10. public static void main(String[] args) {
  11. SubClassA subClass = new SubClassA();
  12. // SuperClass superClass = new SuperClass();
  13. testFiled(subClass.getClass());
  14. // testFiled(superClass.getClass());
  15. }

运行结果:

  1. 分割线: 》》》》》》》》》》》》》》》 start
  2. clazz.getSimpleName():SubClassA
  3. getFields:subPublicName,publicName
  4. getDeclaredFields:finalStr,finalStaticStr,staticStr,subName,subGender,subPublicName,subPrivateName,subProtectedName,subDefaultName

测试final/static/fianl static 字段的访问、赋值:

  1. @Test
  2. public void testFieldAccess() {
  3. try {
  4. SubClassA a = new SubClassA();
  5. Field f = null;
  6. // 访问 final、static、final static 修饰的 field,其中 final static 修饰的 field 不可再次set。
  7. // static set 后,会影响到其它值。
  8. f = SubClassA.class.getDeclaredField("finalStaticStr");
  9. f.setAccessible(true);
  10. System.out.println(f.get(a));
  11. // 当 field 为静态变量,field.set(obj,value) 与 field.set(null, value),即field 为静态变量时,set 方法的第一个参数 obj 被忽略。
  12. f.set(a, "333");
  13. System.out.println(f.get(a));
  14. } catch (NoSuchFieldException e) {
  15. e.printStackTrace();
  16. } catch (IllegalAccessException e) {
  17. e.printStackTrace();
  18. }
  19. }

final static 字段结果:

  1. java.lang.IllegalAccessException: Can not set static final java.lang.String field com.demo.activiti7.inherit.SubClassA.finalStaticStr to java.lang.String
  2. at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
  3. at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
  4. at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
  5. at java.lang.reflect.Field.set(Field.java:764)
  6. at com.demo.activiti7.inherit.DemoTest.testFieldAccess(DemoTest.java:170)
  7. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  8. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  9. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  10. at java.lang.reflect.Method.invoke(Method.java:498)
  11. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  12. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  13. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  14. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  15. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  16. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  17. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  18. at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  19. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  20. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  21. at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  22. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  23. at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  24. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  25. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
  26. at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
  27. at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
  28. at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
  29. 22

分析:

  1. // getDeclaredField 方法拿取当前类的字段,无论字段的修饰符是什么,都可以拿取。
  2. // Field 的 set 方法,在可访问的情况下,final static 是不可以重新赋值的
  3. // 源码
  4. /**
  5. * Sets the field represented by this {@code Field} object on the
  6. * specified object argument to the specified new value. The new
  7. * value is automatically unwrapped if the underlying field has a
  8. * primitive type.
  9. *
  10. * <p>The operation proceeds as follows:
  11. *
  12. * <p>If the underlying field is static, the {@code obj} argument is
  13. * ignored; it may be null.
  14. *
  15. * <p>Otherwise the underlying field is an instance field. If the
  16. * specified object argument is null, the method throws a
  17. * {@code NullPointerException}. If the specified object argument is not
  18. * an instance of the class or interface declaring the underlying
  19. * field, the method throws an {@code IllegalArgumentException}.
  20. *
  21. * <p>If this {@code Field} object is enforcing Java language access control, and
  22. * the underlying field is inaccessible, the method throws an
  23. * {@code IllegalAccessException}.
  24. *
  25. * <p>If the underlying field is final, the method throws an
  26. * {@code IllegalAccessException} unless {@code setAccessible(true)}
  27. * has succeeded for this {@code Field} object
  28. * and the field is non-static. Setting a final field in this way
  29. * is meaningful only during deserialization or reconstruction of
  30. * instances of classes with blank final fields, before they are
  31. * made available for access by other parts of a program. Use in
  32. * any other context may have unpredictable effects, including cases
  33. * in which other parts of a program continue to use the original
  34. * value of this field.
  35. *
  36. * <p>If the underlying field is of a primitive type, an unwrapping
  37. * conversion is attempted to convert the new value to a value of
  38. * a primitive type. If this attempt fails, the method throws an
  39. * {@code IllegalArgumentException}.
  40. *
  41. * <p>If, after possible unwrapping, the new value cannot be
  42. * converted to the type of the underlying field by an identity or
  43. * widening conversion, the method throws an
  44. * {@code IllegalArgumentException}.
  45. *
  46. * <p>If the underlying field is static, the class that declared the
  47. * field is initialized if it has not already been initialized.
  48. *
  49. * <p>The field is set to the possibly unwrapped and widened new value.
  50. *
  51. * <p>If the field is hidden in the type of {@code obj},
  52. * the field's value is set according to the preceding rules.
  53. *
  54. * @param obj the object whose field should be modified
  55. * @param value the new value for the field of {@code obj}
  56. * being modified
  57. *
  58. * @exception IllegalAccessException if this {@code Field} object
  59. * is enforcing Java language access control and the underlying
  60. * field is either inaccessible or final.
  61. * @exception IllegalArgumentException if the specified object is not an
  62. * instance of the class or interface declaring the underlying
  63. * field (or a subclass or implementor thereof),
  64. * or if an unwrapping conversion fails.
  65. * @exception NullPointerException if the specified object is null
  66. * and the field is an instance field.
  67. * @exception ExceptionInInitializerError if the initialization provoked
  68. * by this method fails.
  69. */
  70. /**
  71. 将此Field对象在指定对象参数上表示的字段设置为指定的新值。如果基础字段具有原始类型,则新值将自动解包。
  72. 操作如下:
  73. 如果基础字段是静态的,则obj参数将被忽略;它可以为空。
  74. 否则,基础字段是实例字段。如果指定的对象参数为null,则该方法将引发NullPointerException。如果指定的对象参数不是声明基础字段的类或接口的实例,则该方法将引发IllegalArgumentException。
  75. 如果此Field对象正在实施Java语言访问控制,并且基础字段不可访问,则该方法将引发IllegalAccessException。
  76. 如果基础字段是最终字段,则该方法将抛出IllegalAccessException,除非已成功为此字段对象使用setAccessible(true)并且该字段是非静态的。以这种方式设置最终字段仅在反序列化或重建具有空白最终字段的类的实例时才有意义,然后才可以将它们用于程序的其他部分。在任何其他上下文中使用它可能会产生不可预测的影响,包括程序其他部分继续使用该字段的原始值的情况。
  77. 如果基础字段是原始类型,则尝试展开转换以将新值转换为原始类型的值。如果此尝试失败,则该方法将引发IllegalArgumentException。
  78. 如果在可能的展开之后,新值不能通过标识或扩展转换转换为基础字段的类型,则该方法将引发IllegalArgumentException。
  79. 如果基础字段是静态的,则声明该字段的类将被初始化(如果尚未初始化)。
  80. 该字段设置为可能已展开和扩展的新值。
  81. 如果该字段以obj类型隐藏,则该字段的值将根据前面的规则进行设置。
  82. */
  83. @CallerSensitive
  84. public void set(Object obj, Object value)

1.4 获取方法

Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class...):获取某个publicMethod(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有publicMethod(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

调用静态方法

  • 如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。

调用非public方法

  • 和Field类似,对于非public方法,我们虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用。
  • setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。

    1.5 构造方法

    调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。 为了调用任意的构造方法,Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例。Constructor对象和Method非常类似,不同之处仅在于它是一个构造方法,并且,调用结果总是返回实例;

通过Class实例获取Constructor的方法如下:

  • getConstructor(Class...):获取某个publicConstructor
  • getDeclaredConstructor(Class...):获取某个Constructor
  • getConstructors():获取所有publicConstructor
  • getDeclaredConstructors():获取所有Constructor

    注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。

    调用非publicConstructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。

小结

  • Constructor对象封装了构造方法的所有信息;
  • 通过Class实例的方法可以获取Constructor实例:getConstructor()getConstructors()getDeclaredConstructor()getDeclaredConstructors()
  • 通过Constructor实例可以创建一个实例对象:newInstance(Object... parameters); 通过设置setAccessible(true)来访问非public构造方法。

1.6 获取继承关系(包括 extends 与 implements)

获取父类的 class

  • 使用 getSuperClass

获取接口:

  • 使用 getInterfaces 方法

    注意:getInterfaces()只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型。

1.7 判断是否是继承关系

  • instanceof 方式

    obj instanceof Object

  • 两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom()

    System.out.println(Number.class.isAssignableFrom(Integer.class)); // true

小结
通过Class对象可以获取继承关系:

  • Class getSuperclass():获取父类类型;
  • Class[] getInterfaces():获取当前类实现的所有接口。

通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。

  1. System.out.println(Number.class.isAssignableFrom(Integer.class)); // true Integer 可以向上转型为Number

1.8 动态代理

Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个interface的实例。所谓的动态代理,是与静态代理相对的。
静态代理,就是日常的不同面向接口编写的代码,利用接口 interface inst 变量去接收一个接口的实现类impl,通过 inst 来调用相关的方法(通过接口调用)。
譬如:

  1. // 定义接口
  2. public interface Demo {
  3. void hello(String name);
  4. }
  5. // 接口实现
  6. public class DemoImpl implement Demo {
  7. @Override
  8. public void hello(String name) {
  9. System.out.println("hello " + name);
  10. }
  11. }
  12. ///////////////////////////////
  13. // 创建实例,转用接口调用
  14. Demo demo = new DemoImpl();
  15. demo.hello("Bruce");

在运行期动态创建一个interface实例的方法如下:

  1. 定义一个InvocationHandler实例,它负责实现接口的方法调用;
  2. 通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
    1. 使用的ClassLoader,通常就是接口类的ClassLoader
    2. 需要实现的接口数组,至少需要传入一个接口进去;
    3. 用来处理接口方法调用的InvocationHandler实例。
  3. 将返回的Object强制转型为接口。

完整代码

  1. package com.demo.activiti7.inherit;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.util.Objects;
  6. import org.apache.commons.lang3.StringUtils;
  7. import org.junit.Test;
  8. public class TestDynamicProxy {
  9. // 静态代理
  10. @Test
  11. public void testStaticProxy() {
  12. Demo demo = new DemoImpl();
  13. demo.hello("Bruce");
  14. }
  15. // 动态代理
  16. @Test
  17. public void testDynamic() {
  18. InvocationHandler invocationHandler = new InvocationHandler() {
  19. @Override
  20. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  21. System.out.println("proxy class:" + proxy.getClass());
  22. String name = method.getName();
  23. System.out.println("method:" + name);
  24. System.out.println("args:" + (Objects.isNull(args) ? 0 : args.length));
  25. if ("hello".equals(name)) {
  26. System.out.println("proxy invoke hello: hello " + args[0]);
  27. }
  28. return null;
  29. }
  30. };
  31. Demo demo = (Demo) Proxy.newProxyInstance(
  32. Demo.class.getClassLoader(),
  33. new Class[]{Demo.class},
  34. invocationHandler
  35. );
  36. demo.hello("Bruce Bruces");
  37. try {
  38. invocationHandler.invoke(new DemoImpl(),
  39. DemoImpl.class.getDeclaredMethod("hello", String.class),
  40. new Object[] {"Bruce Bruce"});
  41. } catch (Throwable throwable) {
  42. throwable.printStackTrace();
  43. }
  44. }
  45. }
  46. interface Demo {
  47. void hello(String name);
  48. }
  49. class DemoImpl implements Demo {
  50. @Override
  51. public void hello(String name) {
  52. System.out.println("hello " + name);
  53. }
  54. }

动态代理的实质感觉就是一种组合与委托吧。JVM 帮我们生成相应的代码,通过反射调用相关代码。

动态代理实际上是JVM在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法,把上面的动态代理改写为静态实现类大概长这样:

  1. public class HelloDynamicProxy implements Hello {
  2. InvocationHandler handler;
  3. public HelloDynamicProxy(InvocationHandler handler) {
  4. this.handler = handler;
  5. }
  6. public void morning(String name) {
  7. handler.invoke(
  8. this,
  9. Hello.class.getMethod("morning", String.class),
  10. new Object[] { name });
  11. }
  12. }

其实就是JVM帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码),并不存在可以直接实例化接口的黑魔法。

待(学习、确认项)

enum 枚举的类型

  1. @Test
  2. public void testEnum() {
  3. System.out.println(DemoEnum.class);
  4. System.out.println(DemoEnum.class.getSimpleName());
  5. System.out.println(DemoEnum.class.getConstructors());
  6. System.out.println(DemoEnum.class.getDeclaredConstructors());
  7. System.out.println(DemoEnum.class.isEnum());
  8. }

clazz.newInstance() 的局限:只能调用无参的构造器方法,并且构造器是 public ???是的,IllegalAccessException

  1. java.lang.IllegalAccessException: Class com.demo.activiti7.inherit.DemoTest can not access a member of class com.demo.activiti7.inherit.SubClassB with modifiers "private"
  2. at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
  3. at java.lang.Class.newInstance(Class.java:436)
  4. at com.demo.activiti7.inherit.DemoTest.testConstructor(DemoTest.java:163)
  5. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  6. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  7. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  8. at java.lang.reflect.Method.invoke(Method.java:498)
  9. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  10. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  11. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  12. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  13. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  14. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  15. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  16. at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  17. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  18. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  19. at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  20. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  21. at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  22. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  23. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
  24. at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
  25. at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
  26. at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)