一、什么是反射
反射的概念是由smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在lisp和面向对象方面取得了成绩。其中lead/lead++
、openc++ 、metaxa和openjava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。
反射本身并不是一个新概念,尽管计算机科学赋予了反射概念新的含义。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
二、反射的机制有什么作用
通过反射可以使程序代码访问装载到JVM中的类的内部信息。
(1)获取已装载类的成员变量信息.
(2)获取已装载类的方法.
(3)获取已装载类的构造方法信息.
通过”获取已装载类的成员变量信息”功能可以获取JVM中的Class对象,获取了对象之后可以实现很多功能,比方说IOC容器通过反射创建对象、或者是动态代理。
三、反射机制相关的重要的类
类 | 含义 |
---|---|
java.lang.Class | 代表整个字节码。代表一个类型,代表整个类。 |
java.lang.reflect.Method | 代表字节码中的方法字节码。代表类中的方法。 |
java.lang.reflect.Constructor | 代表字节码中的构造方法字节码。代表类中的构造方法。 |
java.lang.reflect.Field | 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。 |
注:必须先获得Class才能获取Method、Constructor、Field。
四、获取Class的方式
如果要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class
(1)Class.forName(“完整类名带包名”) 静态方法
(2)对象.getClass()
(3)任何类型.class
以上三个的返回值都是Class类型
4.1Class 类的常用方法
方法名 | 功能 |
---|---|
static Class forName(String name) | 返回指定类名name 的class对象 |
Object newInstance() | 调用缺省构造函数,返回该class对象的一个实例 |
getName() | 返回次class对象所表示的实体(类、接口、数组、基本类型等) |
Class [] getInterfaces() | 获取当前class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Class getSuperclass() | 返回表示Class所表示的实体的超类的Class |
Constructor[] getConstructor() | 返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
Method getMethod(String name.Class…paramTypes) | 返回一个Method对象,此对象的形参类型为paramType |
五、反射的API
Class 类:代表一个类或接口,在反射中用于获取类的相关信息。可以使用 Class.forName(“className”) 来获取类的 Class 对象。
Constructor 类:代表类的构造函数,可以使用 Class.getConstructors() 获取所有公共构造函数,或者使用 Class.getDeclaredConstructor(parameterTypes) 获取指定参数类型的构造函数。
Field 类:代表类的字段,可以使用 Class.getFields() 获取所有公共字段,或者使用 Class.getDeclaredField(fieldName) 获取指定字段。
Method 类:代表类的方法,可以使用 Class.getMethods() 获取所有公共方法,或者使用 Class.getDeclaredMethod(methodName, parameterTypes) 获取指定方法。
5.1常用的方法
//获取包名、类名
clas.getPackage().getName()//包名
clas.getSimpleName()//类名
clas.getName()//完整类名
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法
六、反射创建对象的两个步骤
1.先获取到这个有参数的构造方法【用ClassgetDeclaredConstructor()方法获取】
2.调用构造方法new对象【用Constructor类的newInstance()方法new对象】
通过反射调用构造方法实例化java对象,如下:
class Test{
public static void main(String[] args) throws Exception {
//不适用反射创建对象
Preson p1 = new Preson();
Preson p2 = new Preson(123, "zhangsan", "2001-10-19", false);
//使用反射机制创建对象(以前)
Class vipClass = Class.forName("javase.reflectBean.Vip");
// 调用无参数构造方法
Object obj1 = PresonClass.newInstance();//Class类newInstance方法
System.out.println(obj1);
//使用反射机制创建对象(现在)
// 调用有参数的构造方法怎么办?
// 第一步:先获取到这个有参数的构造方法
Constructor c1= PresonClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
// 第二步:调用构造方法new对象
Object obj2 = c1.newInstance(321, "lsi", "1999-10-11", true);//Constructor类的newInstance方法
System.out.println(obj2);
// 获取无参数构造方法
Constructor c2 = PresonClass.getDeclaredConstructor();
Object obj3 = c2.newInstance();
System.out.println(obj3);
}
}