【反射1】——Java基础(韩顺平讲解)

蔚落 2024-02-05 18:52 159阅读 0赞

一个需求,引出反射 | 完整的反射使用流程:

在不修改源码的情况下,来控制程序,也符合设计模式中的opc原则(开闭原则:不修改源码,扩容功能)

1、创建配置文件:re.properties

  1. classfullpath=com.reflection.Cat
  2. method=hi

2、创建Cat类

  1. package com.reflection;
  2. public class Cat {
  3. public String name = "招财猫";
  4. public void hi(){
  5. System.out.println("hi!"+ name);
  6. }
  7. public void cry(){
  8. System.out.println(name + "喵喵叫!");
  9. }
  10. }

3、创建调用类:quection,并回顾传统调用的方法,以及反射机制解决的完整流程

  1. package com.reflection;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.lang.reflect.InvocationTargetException;
  6. import java.lang.reflect.Method;
  7. import java.util.Properties;
  8. public class quection {
  9. public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  10. //问题:根据配置文件 re.properties 中的指定信息,创建Cat类 并 调用hi方法;
  11. //传统方法
  12. Cat cat = new Cat();
  13. cat.hi(); // 如果想调用cry方法,只能修改代码;
  14. System.out.println("===========================================");
  15. //反射
  16. //1. 使用Properties类 获取配置文件中的内容
  17. Properties properties = new Properties();
  18. properties.load(new FileInputStream("src\\main\\resources\\re.properties"));
  19. String classfullpath = properties.getProperty("classfullpath").toString();
  20. String method = properties.getProperty("method").toString();
  21. System.out.println("classfullpath:" + classfullpath);
  22. System.out.println("method:" + method);
  23. //2. 使用反射机制解决
  24. Class aClass = Class.forName(classfullpath); //加载类,返回Class类型的对象aClass
  25. Object o = aClass.newInstance(); //通过aClass得到 com.reflection.Cat 类的对象实例
  26. System.out.println("o的运行类型:" + o.getClass());
  27. //通过 aClass 得到 com.reflection.Cat 类的 methodName为“hi”的方法对象
  28. //即:在反射中,可把方法视为对象(万物接对象)
  29. Method method1 = aClass.getMethod(method);
  30. System.out.println("===========================================");
  31. //通过 方法对象 来实现 调用方法; 也就是 通过 method1对象 来调用 Cat类中的方法;
  32. method1.invoke(o);//传统方法:对象.方法(); 反射:方法.invoke(对象);
  33. }
  34. }

在 传统方法调用 和 反射机制 中,若改为调用Cat类中的cry方法:
传统方法需要修改代码,而反射机制只需要修改配置文件即可,将re.properties配置文件中的,method=hi 改为 method=cry

反射机制:

反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。

加载完类后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射。

Java反射机制原理示意图:
在这里插入图片描述

Java反射机制可以完成:

1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时得到任意一个类所具有的成员变量和方法
4、在运行时调用任意一个对象的成员变量和方法
5、生成动态代理

反射相关的主要类:这些类在java.lang.reflection包中

1、java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
2、java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
3、java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
4、java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器

反射相关的主要类的代码应用:

  1. package com.reflection;
  2. public class Cat {
  3. private String name = "招财猫";
  4. public int age = 0;
  5. public Cat() {
  6. }
  7. public Cat(String name) {
  8. this.name = name;
  9. }
  10. public void hi(){
  11. System.out.println("hi!"+ name);
  12. }
  13. public void cry(){
  14. System.out.println(name + "喵喵叫!");
  15. }
  16. }
  17. package com.reflection;
  18. import java.io.FileInputStream;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.Field;
  21. import java.lang.reflect.Method;
  22. import java.util.Properties;
  23. public class reflection01 {
  24. public static void main(String[] args) throws Exception {
  25. //反射
  26. //1. 使用Properties类 获取配置文件中的内容
  27. Properties properties = new Properties();
  28. properties.load(new FileInputStream("src\\main\\resources\\re.properties"));
  29. String classfullpath = properties.getProperty("classfullpath").toString();
  30. String method = properties.getProperty("method").toString();
  31. //2. 使用反射机制解决
  32. Class aClass = Class.forName(classfullpath); //加载类,返回Class类型的对象aClass
  33. Object o = aClass.newInstance(); //通过aClass得到 com.reflection.Cat 类的对象实例
  34. System.out.println("o的运行类型:" + o.getClass());
  35. //通过 aClass 得到 com.reflection.Cat 类的 methodName为“hi”的方法对象
  36. //即:在反射中,可把方法视为对象(万物接对象)
  37. Method method1 = aClass.getMethod(method);
  38. System.out.println("===========================================");
  39. //通过 方法对象 来实现 调用方法; 也就是 通过 method1对象 来调用 Cat类中的方法;
  40. method1.invoke(o);//传统方法:对象.方法(); 反射:方法.invoke(对象);
  41. //java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
  42. //得到name字段;
  43. //getField不能得到私有的属性
  44. Field name = aClass.getField("age");
  45. System.out.println(name.get(o));//传统写法:对象.成员变量 反射:成员变量对象.get(对象)
  46. //java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
  47. Constructor constructor = aClass.getConstructor();//()中可以指定构造器参数类型,返回无参构造器
  48. System.out.println(constructor);//Cat()
  49. Constructor constructor1 = aClass.getConstructor(String.class);//这里传入的String.class 就是String类的Class对象
  50. System.out.println(constructor1);//Cat(String name)
  51. }
  52. }

反射的优点和缺点:

优点: 可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
缺点: 使用反射基本是解释执行,对执行速度有影响。

  1. package com.reflection;
  2. import java.io.FileInputStream;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6. import java.util.Properties;
  7. public class reflection02 {
  8. public static void main(String[] args) throws Exception {
  9. m1();
  10. m2();
  11. m3();
  12. }
  13. //传统方法调用hi
  14. public static void m1() {
  15. Cat cat = new Cat();
  16. long start = System.currentTimeMillis();
  17. for (int i = 0; i < 900000000; i++) {
  18. cat.hi();
  19. }
  20. long end = System.currentTimeMillis();
  21. System.out.println("m1() 耗时:" + (end - start));
  22. }
  23. //反射机制调用方法hi
  24. public static void m2() throws Exception {
  25. Class aClass = Class.forName("com.reflection.Cat"); //加载类,返回Class类型的对象aClass
  26. Object o = aClass.newInstance(); //通过aClass得到 com.reflection.Cat 类的对象实例
  27. Method method1 = aClass.getMethod("hi");//通过 aClass 得到 com.reflection.Cat 类的 methodName为“hi”的方法对象
  28. long start = System.currentTimeMillis();
  29. for (int i = 0; i < 900000000; i++) {
  30. method1.invoke(o);//反射调用方法
  31. }
  32. long end = System.currentTimeMillis();
  33. System.out.println("m2() 耗时:" + (end - start));
  34. }
  35. //反射机制优化调用方法hi
  36. public static void m3() throws Exception {
  37. Class aClass = Class.forName("com.reflection.Cat"); //加载类,返回Class类型的对象aClass
  38. Object o = aClass.newInstance(); //通过aClass得到 com.reflection.Cat 类的对象实例
  39. Method method1 = aClass.getMethod("hi");//通过 aClass 得到 com.reflection.Cat 类的 methodName为“hi”的方法对象
  40. method1.setAccessible(true);
  41. long start = System.currentTimeMillis();
  42. for (int i = 0; i < 900000000; i++) {
  43. method1.invoke(o);//反射调用方法
  44. }
  45. long end = System.currentTimeMillis();
  46. System.out.println("m3() 耗时:" + (end - start));
  47. }
  48. }
  49. =========执行结果============
  50. m1() 耗时:4
  51. m2() 耗时:1187
  52. m3() 耗时:775

反射的简单优化——关闭访问检查:

1、Method 和 Field、Constructor对象都有setAccessible()方法
2、setAccessible作用是启动和禁用访问安全检查的开关
3、参数值为true表示,反射的对象在使用时取消访问检查,提高反射的效率。参数值为false,则表示反射的对象执行访问检查。
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,159人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java B站顺平补充

    声明 我一开始现在慕课看了翁恺老师的Java,但是觉得一些知识点没讲细(感觉对考试也不友好,虽然讲的不错)所以我后来换了韩顺平老师,前面一些稍微简单的内容我基本都说快速跳