一文入门Java反射

反射技术在平时写增删改查的时候是用不到的,但在设计一个框架时,它几乎是不可或缺的存在。它可以在程序运行时动态改变程序的状态。比如动态的给类中的对象进行赋值,再比如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就结束了,希望这是一篇对你有帮助的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值