通常在程序中对象类型都是编译期就确定下来的,而 Java 反射机制的核心是 JVM 在运行时才动态加载类或调用方法、属性,这样对象的类型在编译期是未知的,也就是可以通过反射机制直接创建编译期未知的对象。  
 
反射并没有太多理论基础,主要是熟悉各种 API ,通过反射在运行时获得程序或程序集中每一个类型成员和成员变量的信息。  
基本概念 反射能做什么 
对于任意一个类,都能够知道这个类的所有属性和方法   
对于任意一个对象,都能够调用它的任意一个方法和属性   
 
反射常见用途 
编译期已知类名 如果编译器已知类名、类对象,可以通过反射简写代码(比如工厂模式中去掉条件判断等),或者获取类的私有属性、方法、构造方法等。  
编译期未知类名 无法导入到当前类,可以通过反射动态加载类。通过配置文件或者泛型动态加载。 反射最重要的用途就是开发各种通用框架,动态加载类。很多框架(比如 Spring)都是配置化的(通过 XML 文件配置 JavaBean, Action 等),为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。   
 
基本数据类型类对象 
基本数据类型boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class   
void 类型void.class   
 
获取类对象的方法 
编译器已知类名Class<?> myObjectClass = MyObject.class;   
已有类对象Class<?> clazz = object.getClass();   
已知完整类全名反射Class<?> myObjectClass = Class.forName("com.simple.User");   
类加载器加载二进制字节流Class clazz = classLoader.loadClass("com.***.User");,注意类加载器的双亲委派模型确保能找到该类。只要能拿到 .class 文件对应的二进制字节流,就能通过反射获取 Class 的所有信息。   
类的内部类Class API 可以遍历内部类或者指定类。或者使用完整类全名反射,注意:内部类和外部类之间使用美元符连接 $ :Class<?> myObjectClass = Class.forName("com.simple.User$InnerClass");   
 
每个 Class 在类加载过程中,会将类对象加载到方法区中,确保 JVM 中只存在一个类对象,它保存了类相关的类型信息,属性,方法,构造方法等等。  
常见类和对应 API AnnotatedElementAnnotatedElement 注解元素贯穿了整个反射的基础类。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  interface  AnnotatedElement   {         default  boolean  isAnnotationPresent (Class<? extends Annotation>           annotationClass)   {...}         <T extends Annotation> T getAnnotation (Class<T> annotationClass)  ;          Annotation[] getAnnotations();          default  <T extends Annotation> T[] getAnnotationsByType         (Class<T> annotationClass) {...}          default  <T extends Annotation> T getDeclaredAnnotation         (Class<T> annotationClass) {...}          default  <T extends Annotation> T[] getDeclaredAnnotationsByType         (Class<T> annotationClass) {...}          Annotation[] getDeclaredAnnotations(); } 
 
MemberMember 表示类的成员:字段属性、构造方法、普通方法。  
1 2 3 4 5 6 7 8 9 10 11 12 13 public  interface  Member   {         int  PUBLIC = 0 ;          int  DECLARED = 1 ;          Class<?> getDeclaringClass();     String getName ()  ;          int  getModifiers ()  ;          boolean  isSynthetic ()  ; } 
 
AccessibleObjectAccessibleObject 表示可访问对象,用来修改查询访问控制符。  
1 2 3 4 5 6 7 8 9 public  class  AccessibleObject  implements  AnnotatedElement   {         public  static  void  setAccessible (AccessibleObject[] array, boolean  flag)          throws  SecurityException  {...}    public  void  setAccessible (boolean  flag)  throws  SecurityException  {...}          public  boolean  isAccessible ()   {...}     ... } 
 
GenericDeclarationGenericDeclaration 声明类型变量的接口,代表着泛型。  
1 2 3 4 public  interface  GenericDeclaration  extends  AnnotatedElement   {         public  TypeVariable<?>[] getTypeParameters(); } 
 
FieldField 代表类中的字段、属性。  
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 public  final  class  Field  extends  AccessibleObject  implements  Member   {         public  Class<?> getDeclaringClass() {...}          public  boolean  isEnumConstant ()   {...}          public  boolean  isSynthetic ()   {...}          public  Class<?> getType() {...}          public  Type getGenericType ()   {...}          public  Object get (Object obj)          throws  IllegalArgumentException, IllegalAccessException {...}    public  boolean  getBoolean (Object obj)          throws  IllegalArgumentException, IllegalAccessException {...}    ...     public  double  getDouble (Object obj)          throws  IllegalArgumentException, IllegalAccessException {...}         public  void  set (Object obj, Object value)          throws  IllegalArgumentException, IllegalAccessException {...}    public  void  setBoolean (Object obj, boolean  z)          throws  IllegalArgumentException, IllegalAccessException {...}    ...     public  void  setDouble (Object obj, double  d)          throws  IllegalArgumentException, IllegalAccessException          public  AnnotatedType getAnnotatedType ()   {...}    ... } 
 
ExecutableExecutable 1.8 新增的抽象类,是构造方法和普通方法的基类。  
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 public  abstract  class  Executable  extends  AccessibleObject     implements  Member , GenericDeclaration   {    ...          public  abstract  Class<?>[] getParameterTypes();          public  int  getParameterCount ()   {...}          public  Type[] getGenericParameterTypes() {...}          public  Parameter[] getParameters() {...}          public  boolean  isVarArgs ()    {...}     ...          public  abstract  Annotation[][] getParameterAnnotations();          public  abstract  AnnotatedType getAnnotatedReturnType ()  ;          public  AnnotatedType getAnnotatedReceiverType ()   {...}          public  AnnotatedType[] getAnnotatedParameterTypes() {...}          public  AnnotatedType[] getAnnotatedExceptionTypes() {...}     } 
 
ConstructorConstructor 代表类中的构造方法。  
1 2 3 4 5 6 7 8 9 10 public  final  class  Constructor <T > extends  Executable   {         public  Class<T> getDeclaringClass ()   {...}          public  T newInstance (Object ... initargs)          throws  InstantiationException, IllegalAccessException,                IllegalArgumentException, InvocationTargetException {...}         ... } 
 
MethodMethod 代表类中的普通方法。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  final  class  Method  extends  Executable   {         public  Class<?> getDeclaringClass() {...}     ...          public  Class<?> getReturnType() {...}          public  Type getGenericReturnType ()   {...}     ...               public  Object invoke (Object obj, Object... args)          throws  IllegalAccessException, IllegalArgumentException,            InvocationTargetException {...}         public  boolean  isBridge ()   {...}     ...          public  boolean  isDefault ()   {...}          public  Object getDefaultValue ()   {...} } 
 
ClassClass 反射基石,可以对 .class 文件全解析,获取字段、构造方法、普通方法、内部类、注解等功能。  
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 public  final  class  Class <T > implements  java .io .Serializable ,    GenericDeclaration , Type , AnnotatedElement   {    ...                         public  String getName ()   {...}          public  String toString ()   {...}          public  String getSimpleName ()   {...}          public  String getTypeName ()   {...}          public  String getCanonicalName ()   {...}                    public  static  Class<?> forName(String className){...}          public  static  Class<?> forName(String name, boolean  initialize         , ClassLoader loader)          public  T newInstance ()  throws  InstantiationException,          IllegalAccessException  {...}         public  ClassLoader getClassLoader ()   {...}                    public  Method getEnclosingMethod ()  throws  SecurityException  {...}          public  Constructor<?> getEnclosingConstructor()          throws  SecurityException {...}          public  Class<?> getEnclosingClass() throws  SecurityException {...}          public  Class<?> getDeclaringClass() throws  SecurityException {...}          public  boolean  isAnonymousClass ()   {...}          public  boolean  isLocalClass ()   {...}          public  boolean  isMemberClass ()   {...}          public  Class<?>[] getClasses() {...}          public  Class<?>[] getDeclaredClasses() throws  SecurityException {...}                    public  Field[] getFields() throws  SecurityException {...}          public  Method[] getMethods() throws  SecurityException {...}          public  Constructor<?>[] getConstructors() throws  SecurityException {...}          public  Field getField (String name)          throws  NoSuchFieldException, SecurityException  {...}         public  Method getMethod (String name, Class<?>... parameterTypes)          throws  NoSuchMethodException, SecurityException  {...}         public  Constructor<T> getConstructor (Class<?>... parameterTypes)          throws  NoSuchMethodException, SecurityException  {...}         public  Field[] getDeclaredFields() throws  SecurityException {...}          public  Method[] getDeclaredMethods() throws  SecurityException {...}          public  Constructor<?>[] getDeclaredConstructors()          throws  SecurityException {...}          public  Field getDeclaredField (String name)          throws  NoSuchFieldException, SecurityException  {...}         public  Method getDeclaredMethod (String name, Class<?>... parameterTypes)          throws  NoSuchMethodException, SecurityException  {...}         public  Constructor<T> getDeclaredConstructor (Class<?>... parameterTypes)          throws  NoSuchMethodException, SecurityException  {...}                   public  boolean  isAnnotation ()   {...}          public  <A extends Annotation> A getAnnotation (Class<A> annotationClass)  {}          public  boolean  isAnnotationPresent         (Class<? extends Annotation> annotationClass) {...}          public  <A extends Annotation> A[] getAnnotationsByType         (Class<A> annotationClass) {...}          public  Annotation[] getAnnotations() {...}          public  Annotation[] getDeclaredAnnotations()  {...}               public  AnnotatedType getAnnotatedSuperclass ()   {...}               public  AnnotatedType[] getAnnotatedInterfaces() {...}                    public  TypeVariable<Class<T>>[] getTypeParameters() {...}          public  Type getGenericSuperclass ()   {...}          public  Type[] getGenericInterfaces() {...}                    public  native  Class<? super  T> getSuperclass();          public  Class<?>[] getInterfaces() {...}          public  native  Class<?> getComponentType();          public  native  int  getModifiers ()  ;          public  InputStream getResourceAsStream (String name)   {...}          public  java.net.URL getResource (String name)   {...}          public  boolean  isEnum ()   {...}          public  T[] getEnumConstants() {...}          public  T cast (Object obj)   {...}          public  <U> Class<? extends U> asSubclass(Class<U> clazz) {...}          public  boolean  isSynthetic ()   {...}          public  native  boolean  isArray ()  ;     ... } 
 
get*** 和 getDeclared*** 的区别  
getDeclared*** 获取当前类中所有的字段属性,方法等,包含私有的,但不包含父类。   
get*** 获取公共的字段属性,方法等,包含父类的。   
 
总结 
泛型中类型变量定义声明GenericDeclaration 表示类型变量声明的接口,其实现类为:Class, Constructor, Method,也就是说只有在类、构造方法、普通方法 定义时才能声明类型变量,其他地方不允许。  
 
访问权限控制AccessibleObject 表示可以控制访问权限的对象,其实现类为:Field, Constructor, Method。也就是说只有在字段、构造方法、普通方法 上可以设置访问权限 AccessibleObject.setAccessible(true),并访问非 public 类型。   
 
数组 辅助类 Array Array  提供一系列静态方法用来动态创建和访问数组。  
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 public  final  class  Array   {         public  static  Object newInstance (Class<?> componentType, int  length)          throws  NegativeArraySizeException  {...}       public  static  Object newInstance (Class<?> componentType, int ... dimensions)          throws  IllegalArgumentException, NegativeArraySizeException  {...}         public  static  native  int  getLength (Object array)          throws  IllegalArgumentException ;         public  static  native  Object get (Object array, int  index)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;         public  static  native  boolean  getBoolean (Object array, int  index)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;    ...     public  static  native  double  getDouble (Object array, int  index)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;         public  static  native  void  set (Object array, int  index, Object value)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;         public  static  native  void  setBoolean (Object array, int  index, boolean  z)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;    ...     public  static  native  void  setDouble (Object array, int  index, double  d)          throws  IllegalArgumentException, ArrayIndexOutOfBoundsException ;    
 
定义数组 Java 中可以明确类型定义数组,也可以使用 Object/Class<?> 来表示数组:  
1 2 3 4 5 6 7 String[] strings = {"a" , "b" , "c" }; Class<?> classes = int [].class; Object object = new  int []{1 , 2 , 3 }; Object object1 = Array.newInstance(String.class, 2 ); Object object2 = Array.newInstance(int .class, 2 , 3 , 2 ); 
 
反射中通常使用 Object/Class<?> 来表示参数或返回值,注意:它们同时代表了数组类型。  
判断是否为数组 判断当前类对象或实例是否表示数组,可以使用 Class.isArray() 来判断:  
1 2 3 System.out.println(int [].class.isArray());           System.out.println(strings.getClass().isArray());    System.out.println(object.getClass().isArray());     
 
反射中转换为数组 通过反射调用方法后返回 Object/Class<?> ,可以先判断是否为数组,然后再做转换。转换可以显示强制转换为对应类型数组,也可以通过 java.lang.reflect.Array 辅助类来处理。  
1 2 3 4 5 6 7 8 9 10 11 if  (object.getClass().isArray()) {         int [] converts = (int []) object;     for  (int  i : converts) {         System.out.println(i);     }          System.out.println(Array.get(object, Array.getLength(object) - 1 )); } 
 
示例 实例化 反射创建类实例,有两种方法:  
Constructor.newInstance() 构造方法实例化,可以传递构造方法的参数。   
Class.newInstance() 直接通过类来实例化,相当于构造方法空参数来实例化。   
 
1 2 3 4 5 6 7 8 9 Class<?> clazz = Class.forName("com.ymzs.javabase.reflect.ReflectedClass" ); Object object1 = clazz.newInstance(); System.out.println("object1 = "  + object1); Constructor constructor = clazz.getConstructor(String.class, byte [].class); byte [] paras = {1 , 2 };Object object2 = constructor.newInstance("s" , paras); 
 
获取和设置字段属性 先将类实例化,然后使用该实例修改字段属性;如果是 static 字段,它属于类的字段属性,所以将实例设置为 null。  
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 Class<?> clazz = Class.forName("com.ymzs.javabase.reflect.ReflectedClass" ); Object object = clazz.newInstance(); Field declaredField = clazz.getDeclaredField("mPrivateStr" ); System.out.println("Declared Field is: "  + declaredField); declaredField.setAccessible(true ); String value = (String) declaredField.get(object); System.out.println("get private: "  + declaredField.getName() + " = "  + value); String changeString = "ChangePrivateString" ; declaredField.set(object, changeString); value = (String) declaredField.get(object); System.out.println("set private: "  + declaredField.getName() + " = "  + value); Field publicField = clazz.getField("mSuperClassPublicStr" ); publicField.set(object, "ChangePublicString" ); Field staticPublicField = clazz.getField("sPublicStr" ); staticPublicField.set(null , "changeStaticString" ); 
 
调用方法 先将类实例化,然后使用该实例调用方法;如果是 static 字段,它属于类方法,所以将实例设置为 null。  
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 Class<?> clazz = Class.forName("com.ymzs.javabase.reflect.ReflectedClass" ); Method publicMethod = clazz.getMethod("superPublicMethod" , int .class); Method declaredMethod = clazz.getDeclaredMethod("testPrivateMethod"      , new  Class[]{byte [].class}); Object object = clazz.newInstance(); byte [] parameters = {1 , 0 , 1 };declaredMethod.setAccessible(true ); Object results = declaredMethod.invoke(object, parameters); if  (results.getClass().isArray()){         String[] array = (String[]) results;     String value = "" ;     for  (String s : array){         value += s;     }     System.out.println("Declared method return value: "  + value); } Method staticMethod = clazz.getMethod("staticMethod" , String.class); System.out.println("Static Method return value: "       + staticMethod.invoke(null , "110" )); 
 
内部类 通过反射接口可以获取内部类是在哪个类/构造方法/普通方法 中定义,以及判断它们属于成员/匿名/局部 内部类的哪一种。  
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public  class  OuterClass  {    public  Runnable runnable;          public  class  MemberInnerClass   {     }          public  OuterClass ()  {         runnable = new  Runnable() {             @Override              public  void  run ()   {                              }         };     }          public  Object testMethodClass ()  {         class  MethodClass  {         }         return  new  MethodClass();     } } private  void  testInnerClass ()  {    System.out.println("***********testInnerClass***********" );     OuterClass outerClass = new  OuterClass();     Class<?> clazz = outerClass.testMethodClass().getClass();     System.out.println("Method class from : "  + clazz.getEnclosingMethod());     System.out.println("Outer class is : "  + clazz.getEnclosingClass());     System.out.println("is Method class: "  + clazz.isLocalClass());        clazz = OuterClass.MemberInnerClass.class;     System.out.println("Member class from: "  + clazz.getDeclaringClass());     System.out.println("Outer class is : "  + clazz.getEnclosingClass());     System.out.println("is Member class: "  + clazz.isMemberClass());       clazz = outerClass.runnable.getClass();     System.out.println("Anonymous class from : "           + clazz.getEnclosingConstructor());     System.out.println("Outer class is : "  + clazz.getEnclosingClass());     System.out.println("is Anonymous class = "           + clazz.isAnonymousClass());                                       System.out.println("***********testInnerClass***********" ); } Method class from :public java.lang.Object com.*.OuterClass.testMethodClass() Outer class is : class com.***.OuterClass is Method class: true Member class from: class com.***.OuterClass Outer class is : class com.ymzs.***.OuterClass is Member class: true Anonymous class from : public com.***.OuterClass() Outer class is : class com.***.OuterClass is Anonymous class   = true  
 
反射常见场景 
反射与泛型 反射与泛型的混合使用在很多框架中都会出现,应用非常广泛。基础知识点可以参考Java Type类型  ,主要是通过反射获取泛型相关信息。   
反射与注解 反射是注解解析方式的一种,在运行时解析注解并实现对应功能。   
动态代理 代理模式的一种,通过反射动态生成代理对象。设计模式参考:代理模式    
 
动态代理 代理模式:为其他对象提供一种代理以控制对这个对象的访问。  这是设计模式中对代理模式的介绍,代理模式分为静态代理和动态代理。静态代理即编译期前代码及代理关系就已经明确存在;动态代理是通过反射机制动态地生成代理对象,也就是代码编译中并不知道代理关系,动态代理将代理和被代理对象进行了解耦。Java 反射技术是在内存中,动态生成一个新类来实现动态代理。  
Java 中只能为接口 interface 实现动态代理 。  
 
基础类 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 public  interface  InvocationHandler   {         public  Object invoke (Object proxy, Method method, Object[] args)          throws  Throwable ;} public  class  Proxy  implements  Serializable   {              public  static  Class<?> getProxyClass(ClassLoader loader,         Class<?>... interfaces) throws  IllegalArgumentException               public  static  Object newProxyInstance (ClassLoader loader,          Class<?>[] interfaces, InvocationHandler h)         throws  IllegalArgumentException  {...}    ... } 
 
示例 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 47 48 // 1. 目标接口,被动态代理 public interface Subject {     void operation(); } // 2. RealSubject,真实对象 public class RealSubject implements Subject{     public void operation(){         System.out.println("RealSubject::operation.");     } } // 3. DynamicProxy,实现动态代理 public class DynamicProxy implements InvocationHandler{     private Object object;     public DynamicProxy(Object object) {         this.object = object;     }     @Override     public Object invoke(Object o, Method method, Object[] objects)          throws Throwable {         // 可以在这里增加权限控制,或者添加其他功能         ...         Object result = method.invoke(object, objects);         ...         return result;     } } // 4. Test public class TestDynamicProxy {     public static void main(String[] args) {         RealSubject realSubject = new RealSubject();         InvocationHandler dynamicProxy = new DynamicProxy(realSubject);         Subject subject = (Subject) Proxy.newProxyInstance(                 Subject.class.getClassLoader(),                 new Class[]{Subject.class}, dynamicProxy);         System.out.println(subject.getClass());         subject.operation();     } } // 5. Result class com.sun.proxy.$Proxy0 RealSubject::operation. 
 
InvocationHandler.invoke 在这里实现动态代理,同时可以在动态代理前增加权限检查,或者添加功能(相当于装饰模式)。   
com.sun.proxy.$Proxy0 从输出的 Log 可以看出,动态代理是重新生成了一个新的类 com.sun.proxy.$Proxy0,并实现了动态代理的功能。新类命名格式:包名 + $Proxy + id 序号。     
 
ClassDump 工具工具介绍 ClassDump 是 HotSpot 虚拟机特有的,它是 HotSpot SA: Serviceability Agent 中的一个工具。ClassDump 可以在运行时 dump 类文件,特别是动态生成或者运行时被修改了字节码的类。HotSpot 有一套私有 API 提供了对 JVM 内部数据结构的审视功能,称为 Serviceability Agent。可以通过 API 直接写 Java 代码来查看一个跑在 HotSpot 上的 Java 进程的内部状态。它也提供了一些封装好的工具,可以直接在命令行上跑,包括 ClassDump 工具。SA 的一个重要特征是它是“进程外审视工具”。也就是说 SA 并不运行在要审视的目标进程中,而是运行在一个独立的 Java 进程中,通过操作系统上提供的调试 API 来连接到目标进程上。这样 SA 的运行不会受到目标进程状态的影响,因而可以用于审视一个已经挂起的 Java 进程。一个被调试器连接上的进程会被暂停下来。所以在 SA 连接到目标进程时,目标进程也是一直处于暂停状态的,直到 SA 解除连接。如果需要在线上使用SA的话需要小心,不要通过 SA 做过于耗时的分析,宁可先把数据都抓出来,把连接解除掉之后再离线分析。目前的使用经验是,连接上一个小 Java 进程的话很快就好了,但连接上一个“大”的 Java 进程(堆比较大、加载的类比较多)可能会在连接阶段卡住好几分钟,线上需要慎用。ClassDump 的特点:需要目标 Java 进程必须在运行中;连接时会导致目标进程暂停。  
示例过滤器 示例:使用 ClassDump 工具 Dump 出动态代理生成的类,其类特点是文件名都是 com.sun.proxy.$Proxy 开头的 class 文件。  
1 2 3 4 5 6 7 8 9 10 11 12 13 import  sun.jvm.hotspot.oops.InstanceKlass;import  sun.jvm.hotspot.tools.jcore.ClassFilter;public  class  MyClassNameFilter  implements  ClassFilter   {    private  static  final  String CLASSNAME_PREFIX = "com/sun/proxy/$Proxy" ;     @Override      public  boolean  canInclude (InstanceKlass instanceKlass)   {         String klassName = instanceKlass.getName().asString();         return  klassName.startsWith(CLASSNAME_PREFIX);     } } 
 
注意:过滤器中需要过滤的类名是以 / 分割的而不是 . ,如:com/sun/proxy/$Proxy 。  
执行过程 
当前是在 Ubuntu 环境中运行的,执行时必须使用 root 权限(使用 sudo 也会报错)。  
 
修改动态代理源文件,确保进程持续运行 。  
1 2 3 4 5 6 7 8 9 public  class  TestDynamicProxy   {    public  static  void  main (String[] args)   {         RealSubject realSubject = new  RealSubject();         ...         subject.operation();                  System.in.read();     } } 
 
运行该测试程序,并查看对应的进程名:  
1 2 3 4 5 // 找到目标进程 id: 81249 root@server005:~/classdump# jps 83496 Jps 119412 ServerLauncher 81249 TestDynamicProxy 
 
MyClassNameFilter.java 文件并不需要编译(也编译不过导入的包名找不到),在 MyClassNameFilter.java 文件所在目录运行,命令使用方法 :  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 0. root 用户下执行 // 1. 指定过滤器类文件为 MyClassNameFilter // 2. 指定 classdump 进程 id:81249 root@server005:~/classdump# java -classpath "$JAVA_HOME/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=MyClassNameFilter sun.jvm.hotspot.tools.jcore.ClassDump 81249 Warning: Can not create class filter! Attaching to process ID 81249, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.121-b00 root@server005:~/classdump# tree com/ com/ └── sun     └── proxy         └── $Proxy0.class 2 directories, 1 file 
 
执行完毕后,会生成三个代码目录:com, java, sun,其中 com 为动态代理中生成的类,其他为加载的系统类。  
没有使用 root 账号运行出现的错误:  
1 2 3 4 5 6 7 8 // 1. 直接使用其他账户运行,无法 attach 到目标进程 Warning: Can not create class filter! Attaching to process ID 80662, please wait... Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process // 2. sudo 运行,无法打开对应库文件 Attaching to process ID 81297, please wait... Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: cannot open binary file 
 
结果分析 使用 jd-gui 打开 $Proxy0.class 文件分析动态代理生成的类实现了哪些功能:  
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public  final  class  $Proxy0   extends  Proxy    implements  Subject   {  private  static  Method m1;   private  static  Method m0;   private  static  Method m3;   private  static  Method m2;      public  $Proxy0(InvocationHandler paramInvocationHandler)   {     super (paramInvocationHandler);   }         static    {     try      {                            m1 = Class.forName("java.lang.Object" ).getMethod("equals" ,          new  Class[] { Class.forName("java.lang.Object" ) });       m0 = Class.forName("java.lang.Object" ).getMethod("hashCode" ,          ew Class[0 ]);       m3 = Class.forName("Subject" ).getMethod("operation" , new  Class[0 ]);       m2 = Class.forName("java.lang.Object" ).getMethod("toString" ,          new  Class[0 ]);       return ;     }     ..   }      public  final  boolean  equals (Object paramObject)     {    ..       return  ((Boolean)this .h.invoke(this , m1,          new  Object[] { paramObject })).booleanValue();     ...   }      public  final  String toString ()     {    ...       return  (String)this .h.invoke(this , m2, null );     ...   }      public  final  int  hashCode ()     {    ...       return  ((Integer)this .h.invoke(this , m0, null )).intValue();     ...   }         public  final  void  operation ()     {    try      {       this .h.invoke(this , m3, null );       return ;     }     catch  (Error|RuntimeException localError)     {       throw  localError;     }     catch  (Throwable localThrowable)     {       throw  new  UndeclaredThrowableException(localThrowable);     }   } 
 
可以看出生成的代理类,最终是通过 InvocationHandler 来调用目标方法的。  
参考文档