定义
Java反射,指的是在运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。这也是Java被称为准动态语言的关键。
在Java中,反射机制相关的类在java.lang.reflect.* 包下。
之所以可以使用反射是因为一个类再堆内存中只有唯一一个java.lang.Class对象。Class对象是用来封装类再方法区内的数据结构,类的加载的最终产品是位于堆区中的 Class对象, Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
反射机制中重要的类
1、java.lang.class:代表整个字节码。代表一个类型,代表整个类。
2、java.lang.reflect.Method:代表类中的方法。
3、java.lang.reflect.Constructor:代表类中的构造方法。
4、java.lang.reflect.Field:代表类中的成员变量(静态变量+实例变量)
获取class的三种方式
1、Class.forName("完整类名(带包名)") -- 这种方式是静态方法
Class c = Class.forName("com.test.statical.UserServiceImp");
注:会抛出ClassNotFoundException异常
Class.forName()方法也是类加载的一种方式,类加载有3中方式:
(1)命令行启动应用时候由JVM初始化加载
(2)通过Class.forName()方法动态加载
(3)通过ClassLoader.loadClass()方法动态加载
其中:Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
2、对象.getClass
Class c2 = userServiceImp.getClass();
3、任何类型.class
Class c1 = UserServiceImp.class;
通过反射实例化对象
对象.newInstance()
引申创建对象的三种方式:
(1)new 对象
(2)clone
(3)反射的方式创建对象.newInstance()
.newInstance()方法内部实际上调用了无参构造方法,必须要保证class内部的无参构造方法存在。
否则会抛出java.lang.InstantiationException异常。
通过.newInstance()方法会导致类加载,类中的静态代码块会被执行。
通过反射反编译一个类的属性(映照上面4种反射类)
1、Class类方法
| 方法名 | 备注 |
|---|---|
| public T newInstance() | 创建对象 |
| public String getName() | 返回完整类名带包名 |
| public String getSimpleName() | 返回类名 |
| public Field[] getFields() | 返回类中public修饰的属性 |
| public Field[] getDeclaredFields() | 返回类中所有的属性 |
| public Field getDeclaredField(String name) | 根据属性名name获取指定的属性 |
| public Method[] getDeclaredMethods() | 返回类中所有的实例方法 |
| public Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 根据方法名name和方法形参获取指定方法 |
| public Constructor<?>[] getDeclaredConstructors() | 返回类中所有的构造方法 |
| public Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 根据方法形参获取指定的构造方法 |
| public native Class<? super T> getSuperclass() | 返回调用类的父类 |
| public Class<?>[] getInterfaces() | 返回调用类实现的接口集合 |
2、File类方法
| 方法名 | 备注 |
|---|---|
| public String getName() | 返回属性名 |
| public Class<?> getType() | 以Class类型,返回属性类型【一般配合Class类的getSimpleName()方法使用】 |
| public void set(Object obj, Object value) | 设置属性值 |
| public Object get(Object obj) | 读取属性值 |
注意:set()方法不可以访问私有属性,若想访问私有属性则需要打破封装。
| 方法 | 备注 |
|---|---|
| public void setAccessible(boolean flag) | 默认false,设置为true为打破封装 |
无论是使用get()方法还是set()方法都需要结合对象.属性的方式获取file。(还是需要先获得对象才能拿到属性)
3、Method类方法
| 方法 | 备注 |
|---|---|
| public String getName() | 返回方法名 |
| public Class<?> getReturnType() | 以Class类型,返回方法类型【一般配合Class类的getSimpleName()方法使用】 |
| public Class<?>[] getParameterTypes() | 返回方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】 |
| public Object invoke(Object obj, Object… args) | 调用方法 |
用反射的方式调用方法:
方法.invoke(对象,实参)
4、Constructor类方法
| 方法 | 备注 |
|---|---|
| public String getName() | 返回构造方法名 |
| public Class<?>[] getParameterTypes() | 返回构造方法的修饰符列表(一个方法的参数可能会有多个。)【结果集一般配合Class类的getSimpleName()方法使用】 |
| public T newInstance(Object … initargs) | 创建对象【参数为创建对象的数据】 |
用反射创建对象的两种方式:
(1)调用无参构造方法
Class vipClass = Class.forName("javase.reflectBean.Vip");
Object obj1 = vipClass.newInstance();//Class类的newInstance方法
(2)调用有参构造方法
Constructor c1 = vipClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
Object obj2 = c1.newInstance(321, "lsi", "1999-10-11", true);//Constructor类的newInstance方法
注意:
- 属性最重要的是名字
- 实例方法最重要的是名字和形参列表
- 构造方法最重要的是形参列表
获取一个类的父类以及实现的接口
Class superclass = vipClass.getSuperclass();
Class[] interfaces = vipClass.getInterfaces();