spring中的java基础(反射)

spring中的java基础(反射)

反射

一、反射机制

反射就是在运行的状态下,对于任何一个类,都能够知道自己的所有属性和方法:对于任何一个方法和属性,这种动态获取信息和调用对象的方法叫做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 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:人

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×