1、什么是反射?

➢Reflection (反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 Class C = Class.forName(“java.lang.String”) ➢加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一 个类只有一-个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到 类的结构。这个对象就像一面镜子, 透过这个镜子看到类的结构,所以,我们形象的称之为:反射

image.png

2、反射机制能做些什么?

➢在运行时判断任意一个对象 所属的类
➢在运行时构造任意一个类的对象
➢在运行时判断任意一个类所具有的成员变量和方法
➢在运行时获取泛型信息
➢在运行时调用任意一个对象的成员变量和方法
➢在运行时处理注解
➢生成动态代理
image.png

3、如何获取反射对象

3.1、class详解,反射操作的源头,获取class的几种方法

所有反射得来源都是操作class类,通过获取class类对反射进行操作

3.1.1、class类描述

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一-个不变的Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[)的有关信息。
➢Class 本身也是一个类
➢Class 对象只能由系统建立对象
➢加载的类在JVM中只会有一个Class实例
➢一个Class对象对应的是- -个加载到JVM中的一个.class文件
➢每个类的实例都会记得自己是由哪个Class实例所生成
➢通过Class可以完整地得到一个类中的所有被加载的结构
➢Class类 是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
image.png

3.1.2、class类常用方法

image.png

3.1.3、获取class类得常用几种方法

  1. package com.haoker.reflection;
  2. /**
  3. * @ClassName GetClass
  4. * @Description TODO
  5. * @Author 豪
  6. * @Date 2021/8/2 21:38
  7. * @Version I. 0
  8. **/
  9. public class GetClass {
  10. public static void main(String[] args) throws ClassNotFoundException {
  11. //1、通过类名.class获得
  12. Class c1 = User.class;
  13. System.out.println(c1);
  14. //2、通过forName获得
  15. Class c2 = Class.forName("com.haoker.reflection.User");
  16. System.out.println(c2);
  17. //3、通过new对象后getClass方法获得
  18. Class c3 = new User().getClass();
  19. System.out.println(c3);
  20. //获取父类
  21. Class superclass = c1.getSuperclass();
  22. System.out.println(superclass);
  23. }
  24. }
  25. class User{
  26. private String empName;
  27. private String empNo;
  28. public String getEmpName() {
  29. return empName;
  30. }
  31. public void setEmpName(String empName) {
  32. this.empName = empName;
  33. }
  34. public String getEmpNo() {
  35. return empNo;
  36. }
  37. public void setEmpNo(String empNo) {
  38. this.empNo = empNo;
  39. }
  40. }

image.png

4、反射具体操作

4.1、获取运行时类得详细信息

  1. package com.haoker.reflection;
  2. import com.haoker.annotations.ColCopy;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6. /**
  7. * @ClassName GetClass
  8. * @Description 反射获取类得名称、属性、方法、构造方法、注解和泛型
  9. * @Author 豪
  10. * @Date 2021/8/2 21:38
  11. * @Version I. 0
  12. **/
  13. public class GetClassInfo {
  14. public static void main(String[] args) throws Exception, IllegalAccessException {
  15. //1、通过forName获得
  16. Class c2 = Class.forName("com.haoker.reflection.User2");
  17. System.out.println(c2);
  18. //2、获取类全路径名称
  19. String name = c2.getName();
  20. System.out.println(name);
  21. //3、获取类名,不包含路径
  22. String simpleName = c2.getSimpleName();
  23. System.out.println(simpleName);
  24. //获取类所有得属性,只获取共有属性
  25. Field[] fields = c2.getFields();
  26. for (Field field : fields) {
  27. System.out.println(field);
  28. }
  29. //获取类所有得属性,包括私有属性
  30. Field[] declaredFields = c2.getDeclaredFields();
  31. for (Field declaredField : declaredFields) {
  32. System.out.println(declaredField);
  33. }
  34. //获取类指定属性
  35. Field empName = c2.getDeclaredField("empName");
  36. System.out.println(empName);
  37. //获取类指定属性,共有
  38. Field empName2 = c2.getField("age");
  39. System.out.println("获取类指定属性,共有" + empName2);
  40. //获取本类和父类得全部方法
  41. Method[] methods = c2.getMethods();
  42. for (Method method : methods) {
  43. System.out.println("获取本类和父类所有方法" +method);
  44. }
  45. //获取本类所有方法
  46. Method[] methods2 = c2.getDeclaredMethods();
  47. for (Method method : methods2) {
  48. System.out.println("获取本类所有方法" + method);
  49. }
  50. //获取类指定方法,方法名和入参
  51. Method methods3 = c2.getMethod("getEmpName",null);
  52. System.out.println(methods3);
  53. Method methods4 = c2.getMethod("setEmpName",String.class);
  54. System.out.println(methods4);
  55. //获取全部得构造器
  56. Constructor[] constructors = c2.getConstructors();
  57. for (Constructor constructor : constructors) {
  58. System.out.println(constructor);
  59. }
  60. //获取全部得构造器
  61. Constructor[] declaredConstructors = c2.getDeclaredConstructors();
  62. for (Constructor constructor : declaredConstructors) {
  63. System.out.println(constructor);
  64. }
  65. //获取指定名称得构造器
  66. Constructor constructor = c2.getDeclaredConstructor();
  67. System.out.println(constructor);
  68. Constructor constructor2 = c2.getDeclaredConstructor(String.class,String.class,String.class);
  69. System.out.println(constructor2);
  70. //操作注解,看注解得位置再哪里,再属性上,就需要先获取到属性
  71. Field empName3 = c2.getDeclaredField("empName");
  72. if(empName3.isAnnotationPresent(ColCopy.class)){
  73. ColCopy empName1 = empName3.getAnnotation(ColCopy.class);
  74. System.out.println(empName1.name());
  75. }
  76. //操作泛型,泛型一般都是再方法中,所以先要操作方法,再获取泛型对应得实体,因为泛型再程序编译完成后,会编译成具体对应得类
  77. }
  78. }
  79. class User2{
  80. @ColCopy(name ="empName")
  81. private String empName;
  82. private String empNo;
  83. public String age;
  84. public User2() {
  85. }
  86. public User2(String empName, String empNo, String age) {
  87. this.empName = empName;
  88. this.empNo = empNo;
  89. this.age = age;
  90. }
  91. public String getEmpName() {
  92. return empName;
  93. }
  94. public void setEmpName(String empName) {
  95. this.empName = empName;
  96. }
  97. public String getEmpNo() {
  98. return empNo;
  99. }
  100. public void setEmpNo(String empNo) {
  101. this.empNo = empNo;
  102. }
  103. public String getAge() {
  104. return age;
  105. }
  106. public void setAge(String age) {
  107. this.age = age;
  108. }
  109. }

4.2、对方法、属性、构造函数进行操作

  1. package com.haoker.reflection;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. /**
  6. * @ClassName GetClass
  7. * @Description 反射获取类得方法,然后对方法进行执行
  8. * 反射获取属性值,然后对属性进行赋值
  9. * @Author 豪
  10. * @Date 2021/8/2 21:38
  11. * @Version I. 0
  12. **/
  13. public class GetClassIovoke {
  14. public static void main(String[] args) throws Exception, IllegalAccessException {
  15. //1、通过forName获得
  16. Class c2 = Class.forName("com.haoker.reflection.User3");
  17. System.out.println(c2);
  18. //2、对方法、属性进行操作得时候,入参是类
  19. User3 o = (User3) c2.newInstance();
  20. //操作构造函数
  21. Constructor declaredConstructor = c2.getDeclaredConstructor(String.class, String.class, String.class);
  22. User3 lin = (User3) declaredConstructor.newInstance("lin", "999", "27");
  23. System.out.println(lin.getEmpName());
  24. //操作方法
  25. Method methods5 = c2.getMethod("setEmpName",String.class);
  26. methods5.invoke(o,"123");
  27. System.out.println(o.getEmpName());
  28. //操作属性得时候
  29. Field empName1 = c2.getDeclaredField("empName");
  30. empName1.setAccessible(true);
  31. empName1.set(o,"333");
  32. System.out.println(o.getEmpName());
  33. }
  34. }
  35. class User3{
  36. private String empName;
  37. private String empNo;
  38. public String age;
  39. public User3() {
  40. }
  41. public User3(String empName, String empNo, String age) {
  42. this.empName = empName;
  43. this.empNo = empNo;
  44. this.age = age;
  45. }
  46. public String getEmpName() {
  47. return empName;
  48. }
  49. public void setEmpName(String empName) {
  50. this.empName = empName;
  51. }
  52. public String getEmpNo() {
  53. return empNo;
  54. }
  55. public void setEmpNo(String empNo) {
  56. this.empNo = empNo;
  57. }
  58. public String getAge() {
  59. return age;
  60. }
  61. public void setAge(String age) {
  62. this.age = age;
  63. }
  64. }

4.3、对注解进行获取操作

  1. //操作注解,看注解得位置再哪里,再属性上,就需要先获取到属性
  2. Field empName3 = c2.getDeclaredField("empName");
  3. if(empName3.isAnnotationPresent(ColCopy.class)){
  4. ColCopy empName1 = empName3.getAnnotation(ColCopy.class);
  5. System.out.println(empName1.name());
  6. }

4.4、对泛型进行操作

  1. package com.haoker.reflection;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.ParameterizedType;
  4. import java.lang.reflect.Type;
  5. import java.util.List;
  6. import java.util.Map;
  7. /**
  8. * @ClassName GetClass
  9. * @Description 反射操作泛型
  10. * @Author 豪
  11. * @Date 2021/8/2 21:38
  12. * @Version I. 0
  13. **/
  14. public class GetClassT {
  15. public void test1(Map<String,User3> maps,List<String> lists){
  16. System.out.println(maps);
  17. }
  18. public static void main(String[] args) throws Exception, IllegalAccessException {
  19. //1、通过forName获得
  20. Class c2 = Class.forName("com.haoker.reflection.GetClassT");
  21. System.out.println(c2);
  22. //获取方法
  23. Method test1 = c2.getMethod("test1", Map.class, List.class);
  24. //获取方法得参数类型
  25. Type[] genericParameterTypes = test1.getGenericParameterTypes();
  26. for (Type genericParameterType : genericParameterTypes) {
  27. //循环继续获取集合里面得真正类型得参数
  28. if(genericParameterType instanceof ParameterizedType){
  29. Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
  30. for (Type parameterType : actualTypeArguments) {
  31. System.out.println(parameterType);
  32. }
  33. }
  34. }
  35. }
  36. }

image.png

5、反射性能和普通new方法对比,优缺点

优点:
➢可以实现动态创建对象和编译,体现出很大的灵活性
优点:
➢对性能有影响。使用反射一般比使用普通得new要慢一点

6、内加载内存分析

6.1、类加载的过程,主要第一步类得加载得时候会把class文件生成

image.png

image.png
image.png

6.2、分析类初始化

image.png

6.3、类加载器

image.png
image.png

6.4、双亲委派机制

6.4.1、双亲委派机制原理

白话文得说法:遇到事情得时候,儿子先不处理问题,先向父亲反馈,然后父亲再向爷爷反馈,看爷爷能不能处理,爷爷不能处理,再告诉父亲,看父亲能不能处理,不能再让儿子处理。意思就是,类加载得时候,类加载器先一级一级向父级请求,然后父级再一级一级往下查找由谁加载,就好像金字塔那样子得走向。
image.png

6.4.2、如何破环双亲委派机制

双亲委派,就是一级一级往上找,然后再往下找。为了能够保证唯一性而不错乱。只要把唯一性不错乱给破坏了,自然而然把双亲委派破坏了。

1、自定义类加载器 ,重写loadclass方法,这样就会存在多个相同得类,导致双亲委派破坏

java反射 - 图14

7、思考题

7.1、能不能自己写-一个限定名为java.lang.String的类,并在程序中调用它?

分情况,如果只是单纯得再java项目中,新建一个java.lang得包,然后再新建这个string类,然后main函数启动,是不行得,因为根据双亲委派机制,会一级一级往上找,找到得不是我们自己建得类,而找到得类中,是没有main方法得,所以,无法运行程序!但是,如果是再web项目中,可以在WEB-INF/clsssess目录下创建对应得string类,此时程序加载得时候,读取得是我们自己建得string类,但是这样原来得string类得方法都不能用了。