一、什么是反射(机制)
反射实际是一个 ”正“ 和 ”反“ 的操作,所谓的 ”正“ 操作就是用已知的一个类去得到一个对象,继而使用这个对象的属性和方法;而 ”反“ 操作是当我们java文件编译之后形成class文件,每个class文件都是Class类的一个对象,这个对象也可称为文件对象,通过这个文件对象可以得到这个.java类。
二、反射的好处
可以在程序运行过程中,操作这些对象。如下,为什么可以查看到所有的方法列表,就是通过反射机制实现这个功能的,提前把str对象加载进内存,通过反射获取所有的方法封装成Method对象,然后将这些对象放到Method[]数组中展示出来
可以解耦,提高程序的可扩展性。
三、获取Class类对象的方式
如何得到Class类的一个实例化对象?有以下三种方式
第一种:通过Class类内部提供的forName()方法直接根据类的完成路径获取实例化对象
说明:Class.forName("全类名(包含包名)"),因为他是一个字符串可以加载到配置文件中,读取文件加载类。由于字符串支持拼接方便,所以这种方式使用较多!
第二种:通过类.class直接获取Class实例化对象
说明:类名.class:已经将字节码对象加载进内存了,通过类名的属性class获取多用于参数的传递
第三种:使用Object类提供的 public final Class<?> getClass()方法获取一个Class实例化对象
Object是所有类的父类,这样所有类的实例化对象可以直接利用getClass()得到Class类实例化对象
比较三个Class对象,结果都是true
System.out.println(personClass==personClass1);
System.out.println(personClass1==personClass2);
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
四、Class类的实例化对象具有的功能
反射的应用
1、写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
步骤:
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
2、泛型擦除
如何向泛型是String的集合中添加Integer类型的数据,
执行如下代码,编译不通过,数据类型和存储的数据类型不同
List<String> list = new ArrayList<>(); list.add("a"); list.add(1);
伪泛型:编译后的class文件没有泛型的
List<String> list = new ArrayList<>(); list.add("a"); //通过反射获取list的类的文件对象 Class clazz = list.getClass(); //获取list中的add方法 Method method = clazz.getMethod("add",Object.class); //使用方法 method.invoke(list,100); method.invoke(list,50); System.out.println(list);//[a, 100, 50]