反射
一、反射机制
反射就是在运行的状态下,对于任何一个类,都能够知道自己的所有属性和方法:对于任何一个方法和属性,这种动态获取信息和调用对象的方法叫做JAVA的反射机制。
二、理解Class和Class类的常用方法
反射机制可以通过获取Class类来实现,Class也是一个类,只是它是一个描述类的类,也可以生成对象。对于每个类来说,在jre有且只有一个class类型的类,这个class类型只能由系统建立,封装了当前对象所对应的所有信息(属性、方法、构造器,继承和实现哪些接口等)。每个类都知道自己是由哪个Class实例所生成的。要在class中动态获取信息和调用对象方法,就必须要先获取到这个类对应的class实例。获取class实例有三种方法
- 通过类名获取,类名.class
- 通过对象获取,对象.getClass().
- 通过全类名获取,Class.forName(全类名).
这里使用String字符串类来举例
Class clazz = null;
clazz = String.class;
System.out.println(clazz);
clazz = "ReflectionTest".getClass();
System.out.println(clazz);
clazz = Class.forName("java.lang.String");
System.out.println(clazz);
三个输出结果都为 class java.lang.String。
当获取到class实例后,有以下的class类常用方法。
方法名 | 功能说明 |
---|---|
forName(String name) | 返回指定类名name和Class对象 |
newInstance() | 调用默认的构造函数,返回该Class对象的一个实例 |
newInstance(Object []args) | 调用当前格式构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
getSuperClass() | 返回当前Class对象的父类的Class对象 |
getInterfaces() | 获取当前Class对象的接口 |
getClassLoader() | 返回该类的类加载器 |
getSuperclass() | 返回表示此Class所表示的实体的超类的Class |
getField() | 获取类中的public类型的属性 |
getField(String name) | 获取类特定的方法,name参数指定了属性的名称 |
getDeclaredFields() | 获取类中所有的属性(public、protected、default、private),但不包括继承的属性 |
getDeclaredField(String name | 获取类特定的方法,name参数指定了属性的名称 |
getConstructors() | 获取类中的公共方法 |
getConstructors(Class[]params) | 获取类的特定构造方法,params参数指定构造方法的参数类型 |
getDeclaredConstructor() | 获取类中所有的构造方法(public、protected、default、private |
getDeclaredConstructor(Class[]params | 获取类的特定构造方法,params参数指定构造方法的参数类型 |
getMethods() | 获得类的public类型的方法 |
getMethods(String name,Class[]params | 获取类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型 |
getDeclareMethod() | 获取类中所有的方法(public、protected、default、private |
getDeclaredMethod(String name,Class[]param | 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型 |
三、反射的使用
使用在上一文章spring中的java基础(注解)中的自定义注解
CustomDescription和注解容器CustomDescriptions。
Person
@CustomDescription(description = "基类")
@CustomDescription(description = "人")
public class Person {
private String Name;
public String getName(){
return Name;
}
public void setName(String name){
Name = name;
}
public String PersonPublicMethod(String str){
return str;
}
public Person(String name){
Name = name;
}
public String PersonPrivateMethod(String str){
return str;
}
public Person(){
super();
}
}
Student
@CustomDescription(description = "学生")
@CustomDescription(description = "人")
public class Student extends Person {
public String StudentId;
public String getStudentId(){
return StudentId;
}
public void setStudentId(String studentId){
StudentId = studentId;
}
public String StudentPublicMethod(String str){
return str;
}
public String StudentPrivateMethod(String str){
return str;
}
public Student(String name,String studentId){
super(name);
StudentId = studentId;
}
private Student(String name){
super(name);
StudentId = "123456";
}
public Student(){
}
}
1、描述方法Method
描述方法有4个获取方法(getMehods、getMethod、getDeclaredMethods、getDeclareMethod)和1个调用方法(invoke)。
- getMethods
获取clazz对应类中的所有方法,不能获取private方法,且能获取从父类继承的所有方法,包括私有父类的私有方法。 - getMethod
获取clazz对应类中指定方法名和参数类型的方法,不能获取private方法,且获取从父类继承来的所有方法,包括私有的私有方法。因为存在同方法名不同参数这种情况,所以只有同时指定方法名和参数类型才能唯一确定一个方法。 - getDeclaredMethods
获取所有方法,包括私有方法,所有声明的方法,都可以获取到,且只获取当前类的方法。 - getDeclaredMethod
获取clazz对应类制定方法名和参数类型的方法,包括私有方法,所有生命的方法,都可以获取到,且只获取当前类的方法。 - invoke
执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数,私有方法的执行必须在调用invoke之前加上一句“method.setAccessible(true);”。
以下为使用方法例子
//获取student class
clazz = Class.forName("springtest.Reflection.Student");
Method method = null;
Method[] methods = null;
//获取clazz中的所有方法
methods = clazz.getMethods();
for(Method mth:methods){
System.out.print(mth.getName()+" ");
}
System.out.println();
//获取clazz中的指定方法,需要制定方法名和参数类型
method = clazz.getMethod("StudentPublicMethod",String.class);
System.out.println(method.getName()+" ");
System.out.println();
//获取clazz中的所有方法,包括私有方法。但不能获取到父类方法
methods = clazz.getDeclaredMethods();
for (Method mth : methods) {
System.out.print(mth+" ");
}
System.out.println();
method = clazz.getDeclaredMethod("StudentPrivateMethod",String.class);
System.out.println(method.getName() + " ");
//通过类名创建类实例,再通过类实例执行StudentPrivateMethod
Object obje = clazz.newInstance();
method.setAccessible(true);
String result = (String)method.invoke(obje,"inputParams");
System.out.println(result);
执行结果
public void springtest.Reflection.Student.setStudentId(java.lang.String)
public java.lang.String springtest.Reflection.Student.getStudentId()
public java.lang.String springtest.Reflection.Student.StudentPublicMethod(java.lang.String)
public java.lang.String springtest.Reflection.Student.StudentPrivateMethod(java.lang.String)
StudentPrivateMethod
inputParams
2、描述字段Field
描述字段Field方法的使用和描述方法Method中方法的使用有点类似,也是4个获取字段的方法(getFields、getField、getDeclareFields、getDeclaredField)。
- getFields
获得某个类的所有公共(public)字段,包括父类中的字段 - getField
获取某个类public成员变量中指定变量名的字段,包括基类。 - getDeclareFields
获得某个类所有声明的字段,包括public、private和protectd,但是不包括父类的声明字段 - getDeclareField
获取某个类的所有成员变量指定变量名的字段,不包括基类。
以下为获取字段例子
clazz = Class.forName("springtest.Reflection.Student");
System.out.println("---------getDeclaredFields---------");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.print(field.getName()+ " ");
}
System.out.println();
System.out.println("---------getFields---------");
fields = clazz.getFields();
for (Field field : fields) {
System.out.print(field.getName()+" ");
}
System.out.println();
System.out.println("---------getDeclaredField---------");
Field field = clazz.getDeclaredField("StudentId");
field.setAccessible(true);
System.out.println(field.getName());
System.out.println("---------getField---------");
field = clazz.getField("StudentId");
System.out.println(field.getName());
执行结果
---------getDeclaredFields---------
StudentId
---------getFields---------
StudentId
---------getDeclaredField---------
StudentId
---------getField---------
StudentId
设置字段的值
通过反射获得字段,得到字段之后就可以获取或设置字段的值。如果字段是私有的,在获取和设置值的时候都要先调用setAccessible(true)方法,比如在Person中,字段name是私有的
以下为获取字段值和设置字段值例子
//获取类实例
clazz = Class.forName("springtest.Reflection.Person");
//新建对象
Person person = new Person("CYW");
//获取字段
field = clazz.getDeclaredField("Name");
//私有调用setAccessible
field.setAccessible(true);
//通过字段获取字段的值
Object val = field.get(person);
System.out.println(val);
//通过字段设置字段的值
field.set(person,"ivan");
System.out.println(person.getName());
执行结果
CYW
ivan
3、描述构造器Constructor
与描述方法和描述字段差不多,也是有四个方法
- getConstructors
获取对应类中public类型的构造函数,且只获得当前类的构造函数。 - getConstructor
获取对应类中public指定参数类型的构造函数,且只获取当前类的构造函数。 - getDeclalredConstructors
获取对应类中所有构造函数,包括私有构造函数,且只获取当前类的构造函数 - getDeclaredConstructor
获取对应类中指定参数类型的方法,包括私有构造函数,且只获取当前类的方法。
以下为获取构造器,并使用构造器构造实例的例子
//获取类实例
String className = "springtest.Reflection.Student";
Class<Student> clazz1 = (Class<Student>) Class.forName(className);
//通过getConstructors获取该类所有public构造函数
Constructor<Person> [] constructors =
(Constructor<Person>[])Class.forName(className).getConstructors();
for (Constructor<Person> constructor : constructors) {
System.out.println("getConstructors:" + constructor);
}
//通过getDeclaredConstructors该类所有构造函数,包括私有
Constructor<Student>[] constructorsa =
(Constructor<Student>[]) Class.forName(className).getDeclaredConstructors();
for (Constructor<Student> studentConstructor : constructorsa) {
System.out.println("getDeclaredConstructors:"+studentConstructor);
}
//通过getConstructor获取该类public指定参数类型的构造函数
Constructor<Student> constructor = clazz1.getConstructor(String.class,String.class);
System.out.println("getConstructor:"+constructor);
//使用构造器构造student实例
Student obj = constructor.newInstance("cyw","123456");
System.out.println(obj.getName());
//通过getDeclaredConstructor获取该类的指定参数类型的方法,包括私有
constructor = clazz1.getDeclaredConstructor(String.class);
System.out.println("getDeclaredConstructor:"+constructor);
constructor.setAccessible(true);
//使用构造器构造student实例
obj = constructor.newInstance("cyw");
System.out.println(obj.getName());
执行结果
getConstructors:public springtest.Reflection.Student(java.lang.String,java.lang.String)
getConstructors:public springtest.Reflection.Student()
getDeclaredConstructors:public springtest.Reflection.Student(java.lang.String,java.lang.String)
getDeclaredConstructors:private springtest.Reflection.Student(java.lang.String)
getDeclaredConstructors:public springtest.Reflection.Student()
getConstructor:public springtest.Reflection.Student(java.lang.String,java.lang.String)
cyw
getDeclaredConstructor:private springtest.Reflection.Student(java.lang.String)
cyw
4、描述注解Annotation
描述注解主要用getAnnotation(Class<A> annotationClass)方法,返回该元素指定类型的注解,若无注解返回Null
获取注解例子
Class<Student> class2 = (Class<Student>)Class.forName(className);
CustomDescriptions customDescriptions =
class2.getAnnotation(CustomDescriptions.class);
for (CustomDescription customDescription : customDescriptions.value()) {
System.out.println("description:"+customDescription.description());
}
执行结果
description:学生
description:人