• Java重修之旅-反射


    1.什么是反射

      在程序运行过程中,通过借助Reflection API获取任何类的信息,并能直接操作任何对象的属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能称为Java语言的反射机制

    2.反射的作用

    • 在运行时判断任意一个对象所属的类
    • 在运行时判断任意一个类所具有的成员变量和成员方法
    • 在运行时构造任意一个对象
    • 在运行时调用任意一个对象的成员变量和成员方法
    • 动态代理
    • 延伸出各种优秀的框架

    3.使用new创建对象和使用反射创建对象的区别

    • 使用new创建对象,缺乏动态性,你要调用什么方法,使用什么属性,都在编译期确定好了,程序运行后,则无法再进行改变。
    • 使用反射创建对象,是体现Java为动态语言的关键所在,因为在编译期间,一切都是未知的,只有程序运行后,在确定调用什么方法,使用什么属性。通过反射,我们可以在程序运行过程中,去创建对象,调用对象的方法等。

    4.反射的应用场景

      在框架中,几乎处处都用到了反射。框架是一个架子,具体要实现什么功能效果,则是由我们程序员决定的,所以框架不可能在编译期就为我们创建好对象,调用什么方法,如果这样做的话,框架的使用范围就太小了。只有在运行后,再明确这些要求,才能体现出框架的动态性。所以反射是一个框架的灵魂所在

    5.什么是Class对象

      在Java的世界里,一切皆为对象,所以类也不例外,也有相对应的对象Class,即为Class对象。在类的加载过程中,类加载器就会在堆中创建好Class对象,通过该对象,我们就可以在程序运行的过程中,动态去创建对象、调用对象的方法。

    6.反射常用API

    • java.lang.Class:代表一个的对象。
    • java.lang.reflect.Method:代表类的方法对象。
    • java.lang.reflect.Field:代表类的成员变量对象。
    • java.lang.reflect.Constructor:代表类的构造方法对象。

    7.获取Class对象的三种方式

    • 方式一:已知具体的类,通过该类的.class获取,该方式最为安全可靠,程序性能最高。
    1 Class<Person> personClazz = Person.class
    2
    System.out.println("【通过类.class获取Class】===>" + personClazz);
    • 方式二:已知某个类的对象,通过调用该对象的.getClass()方法来获取Class对象。

    1 Person person = new Person();
    2 Class personClass = person.getClass();
    3 System.out.println("【通过对象.getClass()获取Class】===>" + personClass);
    • 方式三:已知一个类的全限定名,且该类在类路径下,则可通过Class类的静态方法forName()获取class对象。
    1 try {
    2    // 可能该路径下不存在该类,所以会抛出ClassNotFoundException异常。
    3    Class<?> personClass2 = Class.forName("fun.jiayou.pojo.Person");
    4    System.out.println("【通过Class.forName()获取Class】===>" + personClass2);
    5 } catch (ClassNotFoundException e) {
    6    e.printStackTrace();
    7 }

    8.使用反射创建对象

    • 方式一:调用Person无参构造器,创建Person对象。
    1 // 使用方式一,来获取Class对象
    2 Class<Person> personClazz = Person.class;
    3 
    4 // 方式一: 调用Person无参构造器,创建Person对象
    5 Person person = personClazz.newInstance();
    6 System.out.println("person = " + person);
    •  方式二:调用Person有参构造器【私有,需要进行暴破】,创建Person对象
    1 Constructor<Person> personConstructor = personClazz.getDeclaredConstructor(String.class, int.class, String.class);
    2 // 对以上构造器进行暴破,然后使用构造器创建对象
    3 personConstructor.setAccessible(true);
    4 Person person1 = personConstructor.newInstance("BaiYun", 21, "Boy");
    5 System.out.println("person1 = " + person1);

    9.使用反射操作属性

    • 根据属性名,获取Field对象
    // 使用方式一,来获取Class对象
    Class<Person> personClazz = Person.class;
    // 1.根据属性名,获取Field对象
    Field name = personClazz.getField("name");
    System.out.println("name = " + name);
    • 根据属性名,获取私有Field对象
    // 2.根据属性名,获取私有Field对象
    Field age = personClazz.getDeclaredField("age");
    age.setAccessible(true);
    System.out.println("age = " + age);
    • 创建Person对象,为该对象属性赋值
    1 Person person = personClazz.newInstance();
    2 Field name1 = personClazz.getDeclaredField("name");
    3 name1.set(person, "BaiYun");
    4 System.out.println(person);
    5 // 获取Person对象的name属性值
    6 System.out.println("name:" + name1.get(person));
    • 获取Person类的所有属性,包括私有属性
    1 // 5.获取Person类的所有属性,包括私有属性
    2 Field[] fields = personClazz.getDeclaredFields();
    3 for (Field field : fields) {
    4     System.out.println("field = " + field.getName());
    5 }

    10.使用反射操作方法

    • 获取所有Person对象的成员方法
    1 Class<Person> personClazz = Person.class;
    2 // 1.获取Person对象的所有方法名
    3 Method[] methods = personClazz.getDeclaredMethods();
    4 for (Method method : methods) {
    5     System.out.println("方法名:"+ method.getName()+",修饰符:" + method.getModifiers() + ",返回值:" + method.getReturnType());
    6 }
    • 调用Person对象公有方法
    1 // 2.调用Person对象公有方法
    2 Person person = personClazz.newInstance();
    3 Method say = personClazz.getMethod("say", null);
    4 System.out.println(say.invoke(person, null));
    • 调用Person对象私有方法
    1 // 3.调用Person对象私有方法
    2 Method eat = personClazz.getDeclaredMethod("eat", null);
    3 // 对该私有方法进行暴破
    4 eat.setAccessible(true);
    5 System.out.println(eat.invoke(person, null));

    ps:如有不足之处,请指出。我们共同进步。

  • 相关阅读:
    Linux mysql 联表查询
    Linux firewalld使用教程+rhce课程实验
    Linux 常用端口
    Linux redhat 7 进入单用户模式
    Linux 子网掩码计算, 二进制十进制互相转换
    Linux 网络配置文件解析
    P1678 烦恼的高考志愿(二分)
    P1563 玩具谜题(简单模拟)
    P1553 数字反转(升级版)(模拟)
    P2690 接苹果 (DP)
  • 原文地址:https://www.cnblogs.com/enroute/p/13962787.html
Copyright © 2020-2023  润新知