反射是指对于任何一个类,在”运行的时候”都可以直接得到这个类全部成分。

  1. 在运行时,可以直接得到这个类的 Class 文件对象(Class)
  2. 在运行时,可以直接得到这个类的构造器对象。(Constructor)
  3. 在运行时,可以直接得到这个类的成员变量对象。(Field)
  4. 在运行时,可以直接得到这个类的成员方法对象。(Method)

    1. Class 对象

    Class 对象包括一个类的全部成分。

    1.1 获取 Class 对象的三种方式

  5. 类名.class;

    1. Class clazz = Student.class;
  6. 类实例对象.getClass():Object 类.public final native Class<?> getClass();

    1. Class clazz = new Student().getClass();
  7. Class.forName(“类的全限名”):Class 类.public static Class<?> forName(String className)

    1. Class clazz = Class.forName("com.zhangshuaiyin.Student");

    1.2 Class 对象常用方法

  8. public String getSimpleName():获得类名字符串:类名

  9. public String getName():获得类的全限定类名:包名+类名 ```java clazz.getSimpleName(); // Student

clazz.getName(); // com.zhangshuaiyin.Student

  1. <a name="fwLXk"></a>
  2. # 2. Constructor 构造器对象
  3. 反射的第一步是先得到Class类对象
  4. <a name="BGAcL"></a>
  5. ## 2.1 获取构造器对象
  6. 1. `Constructor getConstructor(Class... parameterTypes)`:根据参数匹配获取某个构造器,只能拿public 修饰的构造器,几乎不用
  7. 1. `Constructor getDeclaredConstructor(Class... parameterTypes)`:根据参数匹配获取某个构造器,只要声明就可以定位,不关心权限修饰符,建议使用
  8. 1. `Constructor[] getConstructors()`:获取所有的构造器,只能拿 public 修饰的构造器。几乎不用
  9. 1. `Constructor[] getDeclaredConstructors()`:获取所有声明的构造器,只要你写我就能拿到,无所谓权限。建议使用
  10. <a name="L7FWI"></a>
  11. ## 2.2 Constructor 常用方法
  12. 1. `T newInstance(Object... initargs)`:创建对象,注入构造器需要的数据。
  13. 1. `public void setAccessible(boolean flag)`:修改访问权限,true 代表暴力攻破权限(强制访问私有等修饰权限),false 表示保留不可访问权限(暴力反射)
  14. <a name="pr8HI"></a>
  15. # 3. Field 成员变量对象
  16. Field提供有关类或接口的单个字段的信息和动态访问。 反射字段可以是**类(静态)字段**或**实例字段**。
  17. Field允许在 get 或 set 访问操作期间发生扩大转换,但如果发生缩小转换,则会引发IllegalArgumentException 。
  18. <a name="LFRPs"></a>
  19. ## 3.1 获取成员变量对象
  20. 1. `Field getField(String name)`:根据成员变量名获得对应 Field 对象,只能获得 public 修饰的
  21. 1. `Field getDeclaredField(String name)`:根据成员变量名获得对应 Field 对象,只要声明了就可以得到
  22. 1. `Field[] getFields()`:获得所有的成员变量对应的 Field 对象,只能获得 public 修饰的
  23. 1. `Field[] getDeclaredFields()`:获得所有的成员变量对应的 Field 对象,只要声明了就可以得到
  24. <a name="vvNM8"></a>
  25. ## 3.2 Field 常用方法
  26. 1. `public void set(Object obj, Object value)`:给 obj 对象的字段设置 value 值;
  27. 1. obj:成员变量所属对象;
  28. 1. value:要给该成员变量赋的值;
  29. 2. `public Object get(Object obj)`:获取 obj 对象的成员变量的值。
  30. 2. `public Class<?> getType()`:获取属性的类型,返回 Class 对象。
  31. 2. `public String getName()`:获取属性的名称。
  32. 2. `public void setAccessible(boolean flag)`:暴力反射,设置为 true 可以直接访问私有类型的属性。
  33. <a name="GmWrs"></a>
  34. # 4. Method 方法对象
  35. Method 提供有关类或接口上的单个方法的信息和对其的访问。 反映的方法可以是 **类方法 **或 **实例方法(包括抽象方法)**。
  36. 当将要调用的实际参数与基础方法的形式参数进行匹配时, Method 允许发生扩展转换,但如果发生缩小转换,它会抛出 IllegalArgumentException 。
  37. <a name="d5PEm"></a>
  38. ## 4.1 获取方法对象
  39. 1. `public Method getMethod(String name, Class<?>... parameterTypes)`:根据方法名和参数类型获得对应的方法对象,只能获得 public 的
  40. 1. `public Method getDeclaredMethod(String name, Class<?>... parameterTypes)`:根据方法名和参数类型获得对应的方法对象,包括 private 的;
  41. 1. `public Method[] getMethods()`:获得类中的所有成员方法对象,返回数组,只能获得 public 修饰的且包含父类的;
  42. 1. `public Method[] getDeclaredMethods()`:获得类中的所有成员方法对象,返回数组,只获得本类申明的方法。
  43. <a name="i2Cvh"></a>
  44. ## 4.2 Method 常用方法
  45. 1. `public Object invoke(Object obj, Object... args)`
  46. 1. obj:该方法所属对象;
  47. 1. args:方法参数列表;
  48. 2. `public void setAccessible(boolean flag)`
  49. <a name="g1CSJ"></a>
  50. # 5. 反射破坏面向对象的封装性和泛型约束性
  51. 1. 反射可以破坏面向对象的封装性(暴力反射)。
  52. 1. 同时可以破坏泛型的约束性。
  53. 对于破坏泛型约束性的解释:首先要了解一个概念,泛型是工作在编译阶段的,在运行阶段根据类型擦除,标注的泛型会不起作用,而反射作用于运行阶段,这时通过反射获取泛型类对象操作数据是不受泛型约束的。
  54. 比如以下示例:Double 类型的 List 通过反射插入了一个 String 类型的数据而正常运行。
  55. ```java
  56. public class ReflectDemo {
  57. public static void main(String[] args) throws Exception {
  58. // 泛型只能工作在编译阶段,运行阶段泛型就消失了,
  59. // 反射工作在运行时阶段。
  60. List<Double> scores = new ArrayList<>();
  61. scores.add(99.3);
  62. scores.add(199.3);
  63. scores.add(89.5);
  64. // 拓展:通过反射暴力的注入一个其他类型的数据进去。
  65. // a.先得到集合对象的Class文件对象
  66. Class<?> c = scores.getClass();
  67. // b.从ArrayList的Class对象中定位add方法
  68. Method add = c.getDeclaredMethod("add", Object.class);
  69. // c.触发scores集合对象中的add执行(运行阶段,泛型不能约束了)
  70. add.invoke(scores, "波仔");
  71. System.out.println(scores);
  72. }
  73. }