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