反射技术在平时写增删改查的时候是用不到的,但在设计一个框架时,它几乎是不可或缺的存在。它可以在程序运行时动态改变程序的状态。比如动态的给类中的对象进行赋值,再比如spring中通过@Autowired
和@Resource
进行依赖注入,皆通过反射实现。阅读本文,让你了解反射的基本使用方式
@Autowired
private UserService userService;
Java把反射的操作方式抽象成了一个个对象,通过对象对外提供API
Class对象
Class对象是反射中非常重要的东西,他是操作所有类和对象的入口,我们来看这样一个问题:
在Java里万物皆为对象,那么用来实例化对象的 “类” 呢?
实际上, “类” 也不例外,它也是对象,它是“Class”的对象
这怎么理解呢?我们早就知道,每一个学生都有 “name”,“sex”,“age” 这些共有的特征,那么我们就可以将他抽象为一个Student类,像这样的我们自己创建的类叫做自定义类
那么同样的,每一个 自定义类
都毫无例外的有类名
,属性
,方法
这些特征,Java帮我们把这些共有特征抽象成了一个Class基类,通过这个Class基类就可以实例化出Class对象。接下来通过这个Class对象就可以操作到自定义类
的类名,属性,方法这些东西了。
我们先来创建一个用于测试的实体类
package com.minfine.model;
public class StudentModel extends StudentParent implements StudentInterface {
String sid;
public String name;
protected static String sex;
private Integer age;
public StudentModel(){}
public StudentModel(String name, String sex){
this.name = name;
this.sex = sex;
}
public StudentModel(String name, Integer age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "StudentModel{" +
"sid='" + sid + '\'' +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
public void MyStudent(){
System.out.println("run MyStudent");
}
public void MyStudentParam(String name,String sex){
System.out.println(name + "-" + sex);
}
}
interface StudentInterface { }
class StudentParent{ }
Class对象的获取方式
使用反射,首先要拿到前面所说的Class对象,才能进行进一步的操作。Java提供了多种获取Class对象的方式
//通过自定义类获取Class对象
Class class1 = StudentModel.class;
//通过对象获取Class对象
StudentModel model = new StudentModel();
Class class2 = model.getClass();
//通过 Class.forName 方法获取Class对象
try {
Class class3 = Class.forName("com.minfine.model.StudentModel");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//通过类加载器获取Class对象,用的很少
try {
ClassLoader loader = Test.class.getClassLoader();
Class class4 = loader.loadClass("com.minfine.model.StudentModel");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
拿到Class对象以后,我们就可以对它进行下面各种各样的操作了
获取类的信息
Class classes = StudentModel.class;
//获取类实现的接口
Class[] interfaces = classes.getInterfaces();
//获取继承的父类的Class对象(如果没有继承父类,则会返回Object对象,Object是所有对象的父类)
Class superclass = classes.getSuperclass();
//获取自定义类所在的包
Package aPackage = classes.getPackage();
//获取类的注解
Annotation[] annotations = classes.getAnnotations();
实例化对象
通过调用newInstance()
方法,就可以快速实例化出一个对象。它默认调用类的无参构造,如果没有无参构造则会报错。如果需要使用有参构造器实例化对象,则需要使用到下一章的构造器对象Constructor
Object object = classes.newInstance();
//也可以通过强转的方式直接实例化出StudentModel对象
StudentModel object = (StudentModel)classes.newInstance();
构造器
获取构造器对象
我们可以通过反射机制在Java运行时动态创建对象,而对象的创建就需要依赖相应的构造器。反射提供了一个专门的类Constructor
,用于操作构造器和创建对象。获取Constructor
的方式有如下几种
//先获取到Class对象
Class classes = StudentModel.class;
//获取类的所有构造器
Constructor[] constructors = classes.getDeclaredConstructors();
//获取类的空构造器,该方法有会NoSuchMethodException(找不到指定构造器)异常,需要捕捉或抛出
Constructor constructor1 = classes.getDeclaredConstructor();
/**
* 通过形参匹配构造器,比如获取下面这个构造器,则在getConstructor方法中传入两个String的Class对象即可
* public StudentModel(String name, String sex){
* this.name = name;
* this.sex = sex;
* }
**/
Constructor constructor2 = classes.getDeclaredConstructor(String.class,String.class);
实例化对象
获取到Constructor
以后,我们就可以使用它的newInstance()
方法来创建对象啦,这个方法也会有异常,需要捕捉或抛出
//通过无参数的构造器创建对象
Object studentModel = constructor1.newInstance();
//通过有参数的构造器创建对象,还需要传入对应的参数
Object studentModel2 = constructor2.newInstance("张三", "男");
//如果想要得到StudentModel对象,而不是Object,直接强转即可
StudentModel studentModel3 = (StudentModel)constructor1.newInstance();
获取构造器信息
通过这个Constructor
,还可以获取到构造器的修饰符,注解,参数等等
//获取修饰符
String constructorModifier = Modifier.toString(con structor.getModifiers());
//获取标记在构造器的所有注解
Annotation[] constructorAnnotation = constructor.getAnnotations();
//获取标记在构造器上的指定注解,需要传入指定注解的class对象
Annotation constructorAnnotation = constructor.getAnnotation(Params.class);
//获取构造器形参类型
Class[] constructorParams = constructor.getParameterTypes();
//获取构造器形参数量
int count = constructor.getParameterCount();
操作对象属性
反射使用Field
来表达对象的属性,一个Field
对象就代表自定义类的一个属性,获取Fidle
对象的方式有两种:
Class classes = StudentModel.class;
//通过getDeclaredFields方法获取类中的所有属性(会有异常,需要处理)
Field[] fields = classes.getDeclaredFields();
//通过getDeclaredField方法获取指定属性
Field sexField = classes.getDeclaredField("sex");
拿到Fidle
对象以后,即可进一步得到属性的修饰符
,数据类型
等
//获取属性修饰符,如:public,static
String modifiers = Modifier.toString(sexField.getModifiers())
//获取数据类型,如:Integer,String
Class type = sexField.getType();
//获取属性名
String name = sexField.getName();
//获取标记在属性上的全部注解
Annotation[] fieldAnnotations = sexField.getDeclaredAnnotations();
//获取标记在构造器上的指定注解,需要传入指定注解的class对象
Annotation fieldAnnotation = sexField.getAnnotation(Params.class);
操作对象方法
反射使用Method
来表达对象的方法,获取Method
的方法有两种:
Class classes = StudentModel.class;
//通过getDeclaredMethods获取类运行时的所有方法
Method[] declaredMethods = classes.getDeclaredMethods();
/*
通过getDeclaredMethod获取指定的方法,需传入方法名和对应的形参的Class类,比如此方法:
public void MyStudentParam(String name,String sex){
System.out.println(name + "-" + sex);
}
需要使用如下语句获取:
*/
Method method = classes.getDeclaredMethod("MyStudentParam",String.class,String.class);
同样,拿到Method
对象以后,即可通过它进一步得到方法的修饰符
,参数列表
,注解等信息,甚至运行它
//获取方法名
String methodName = method.getName();
//获取方法返回类型
Class methodReturnType = method.getReturnType();
//获取形参参数类型
Class[] paramTypes = method.getParameterTypes();
//获取方法注解
Annotation[] annotations = method.getAnnotations();
//使用invoke方法,我们还可以运行方法。
//invoke方法需要传入运行方法的对象实例,以及方法需要的参数。我们先通过Class对象创建一个Object对象实例,然后即可通过 invoke 运行方法
Class classes = StudentModel.class;
Object o = classes.newInstance();
method.invoke(o,"李四","女");
写到这里,反射的基本API就结束了,希望这是一篇对你有帮助的文章