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:如有不足之处,请指出。我们共同进步。

 

posted @ 2020-11-12 11:01  白雲  阅读(151)  评论(0编辑  收藏  举报