反射:
(一)、反射机制的概念:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以先要获取到每一个字节码文件对应的Class类型的对象。
(1)Class和镜像分别指什么?
Class:一个Class产生的对象是某一个类或者是某一个对象的镜像
镜像:可以获取指定类中所有细节的一个对象
(2)反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
(二)、java.lang.Class类对象怎么被构建?
自己不能构建?(应该是可以通过方法进行构建的)由JVM在执行完类加载后(将class文件读入内存之后)就会给加载进来的这个类构建它的镜像(Class对象);
因为类只加载一次,所以任意一个类的Class对象在内存中都只有一份;
JAVA中类加载成熟的标志:一个类Class对象产生就代表这个类加载结束了。
(三)、Class类对象的构建的三种方式?
(1)Class.forName("全限定名");
(2)类名.class
(3)对象.getClass();
Object o = new Student();
o.getClass();-->构建的是Student
【重点】一个类在运行期间只有一个Class对象产生;
这三种获取Class对象的方式中最常用的是第一种,可以直接传入字符串,也可以写在配置文件中
第二种:需要导包,不导包会出现编译错误,依赖性太强
第三种:有对象了还需要反射干嘛
(四)、Class对象获取成功,就可以通过Class对象获取某个类中的:构造方法、成员方法、成员变量;并调用。
1、获取构造方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法:
参数说明:
Class...:参数为构造器参数的Class类型对象,无参构造器可以不传参数
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法;
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
3)调用构造方法:
调用 Constructor 类中的 newInstance(Object... initargs);参数为可变参数列表,如果构造器需要参数就传入参数,不需要可以不传
获取的私有(默认,受保护)构造器还要设置一个值才能调用:
con.setAccessible(true); //暴力访问(忽略掉访问修饰符)
obj = con.newInstance('男');
2、获取成员方法:
1)批量的:
public Method[] getMethods():获取所有”公有方法”;(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
2)获取单个的:
参数说明:
name : 方法名;
Class … : 形参的Class类型对象
public Method getMethod(String name,Class<?>… parameterTypes):
public Method getDeclaredMethod(String name,Class<?>… parameterTypes)
3)调用方法:
参数说明:
obj:要调用方法的对象;
args:调用方式时所传递的实参;
Method 类中的 public Object invoke(Object obj,Object… args):
调用私有(默认,受保护)方法还需要有如下设置:
m.setAccessible(true);//解除私有限定
3、获取成员变量
1).批量的
Field[] getFields():获取所有的”公有字段”
Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
2).获取单个的:
参数说明:
fieldName:属性的名字;
public Field getField(String fieldName):获取某个”公有的”字段;
public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
3)设置字段的值:
参数说明:
obj:要设置的字段所在的对象;
value:要为字段设置的值;
Field 类中的 public void set(Object obj,Object value):
设置私有(默认,受保护)属性还需要有如下设置:
f.setAccessible(true);//暴力反射,解除私有限定
(五)、反射的应用:框架(打破了java的封装性)
在我们做项目的过程中,我们是不会在每个模块通过直接new对象的方式来获取其他类的实例的,这个直接new对象的方式会造成每个模块的耦合度特别高,如果有100个类都用到了同一个对象,而这100个类都是通过new方式来获取的这个对象,如果这个类改了名字,那么我们就需要去这个一百个类中一个一个的去修改。所以依赖性太强。
在使用spring框架的时候,我们通常是通过读取配置文件或者是使用注解的方式来获取实例的,而这种读取配置文件和使用注解的底层实际上就是使用的反射机制来获取的实例对象。