• Java语法之反射


    一、反射机制

    在前面Java语法之注解自定义注解时我们也有提到反射,要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象。那什么是反射呢?JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。它有点类似照妖镜的作用,不管是什么妖魔鬼怪(类或对象)都能看到它的真面目(获取类的属性方法、调用对象的属性方法)。

    二、Class理解

     反射机制可以动态获取类信息以及调用对象方法,那它是通过什么实现的呢?这就要介绍下Class类了。首先明确Class也是一个类,只是它是一个描述类的类,它也可以生成对象。对于每个类而言,在JRE中有且仅有一个不变的 Class 类型的对象,而这个Class 类型的对象只能由系统建立,封装了当前对象所对应的类的信息,有哪些属性,方法,构造器,实现了哪些接口等等。而且每个类的实例都会记得自己是由哪个Class实例所生成。

     那要获取类信息或调用对象方法,肯定首先要获取到该类或对象对应的Class类的实例。一般获取Class对象有三种方式。

     1. 通过类名获取   类名.class

     2. 通过对象获取   对象.getClass()

     3. 通过全类名获取 Class.forName(全类名)

     这里我们可以使用用字符串来做验证。输出结果都是class java.lang.String。

    package Reflection;
    
    public class ReflectionTest {
        
        public static void main(String[] args) throws ClassNotFoundException {
           //字符串的例子
           Class clazz = null;
           //类名.class
           clazz = String.class;
           System.out.println(clazz);
           //对象.getClass()
           clazz = "ReflectionTest".getClass();
           System.out.println(clazz);
           //Class.forName(全类名)
           clazz = Class.forName("java.lang.String");
           System.out.println(clazz);
    
        }
    
    }
    class java.lang.String
    class java.lang.String
    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

    getFields()

    获取类中public类型的属性

    getField(String name)

    获取类特定的方法,name参数指定了属性的名称

    getDeclaredFields()

    获取类中所有的属性(publicprotecteddefaultprivate),但不包括继承的属性

    getDeclaredField(String name)

    获取类特定的方法,name参数指定了属性的名称

    getConstructors()

    获取类中的公共方法

    getConstructor(Class[] params)

    获取类的特定构造方法,params参数指定构造方法的参数类型

    getDeclaredConstructors()

    获取类中所有的构造方法(publicprotecteddefaultprivate)

    getDeclaredConstructor(Class[] params)

    获取类的特定构造方法,params参数指定构造方法的参数类型

    getMethods()

    获得类的public类型的方法

    getMethod(String name, Class[] params)

    获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型

    getDeclaredMethods()

    获取类中所有的方法(publicprotecteddefaultprivate)

    getDeclaredMethod(String name, Class[] params)

    获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型

     三、反射的使用

     这里要着重介绍下上面API的使用,因为在后面要学习的Spring中IOC的原理就是反射加工厂模式。学好反射API有助于理解Spring框架内部实现。为了演示Class方法的使用,在注解demo的基础上对Person、Student类进行了修改。

    Person类:

    package Reflection;
    
    @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();
        }
        
    }
    View Code

     Student类:

    package Reflection;
    
    @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;
        }
        
        private 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() {
            
        }
    }
    View Code

    一、描述方法Method

    描述方法的主要是4个获取方法getMethods、getMethod、getDeclaredMethods、getDeclaredMethod和1个调用方法invoke。
    getMethods:获取clazz对应类中的所有方法,不能获取private方法,且获取从父类继承来的所有方法包括私有父类的私有方法
    getMethod:获取clazz对应类中指定方法名和参数类型的方法,不能获取private方法,且获取从父类继承来的所有方法包括私有父类的私有方法,因为存在同方法名不同参数这种情况,所以只有同时指定方法名和参数类型才能唯一确定一个方法。
    getDeclaredMethods:获取所有方法,包括私有方法,所有声明的方法,都可以获取到,且只获取当前类的方法。
    getDeclaredMethod:获取clazz对应类中指定方法名和参数类型的方法,包括私有方法,所有声明的方法,都可以获取到,且只获取当前类的方法。
    Invoke:执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数,私有方法的执行,必须在调用invoke之前加上一句method.setAccessible(true);

        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    
            Class clazz = Class.forName("Reflection.Student");
            Method method=null;
            Method[] methods=null;
            
            methods = clazz.getMethods();
            for(Method mth:methods){
                System.out.print(mth.getName()+" ");
            }
            System.out.println();
            
            method = clazz.getMethod("StudentPublicMethod",String.class);
            System.out.print(method.getName()+" ");
            System.out.println();
    
            methods = clazz.getDeclaredMethods();
            for(Method mth:methods){
                System.out.print(mth.getName()+" ");
            }
            System.out.println();
            
            method = clazz.getDeclaredMethod("StudentPrivateMethod",String.class);
            System.out.print(method.getName()+" ");
            System.out.println();
            
            Object obje = clazz.newInstance();
            method.setAccessible(true);
            String result=(String) method.invoke(obje,"inputParams");
            System.out.println(result);
        }

    输出结果:

    StudentPublicMethod setStudentId getStudentId getName setName PersonPrivateMethod PersonPublicMethod wait wait wait equals toString hashCode getClass notify notifyAll 
    StudentPublicMethod 
    StudentPrivateMethod StudentPublicMethod setStudentId getStudentId 
    StudentPrivateMethod 
    inputParams

     二、描述字段Filed
    描述字段Filed方法的使用和描述方法Method中方法的使用有点类似,也是4个获取字段的方法:getFields、getField、getDeclaredFields、getDeclaredField。
    getFields:获得某个类的所有的公共(public)的字段,包括父类中的字段。
    getField:获取某个类public成员变量中指定变量名的字段,包括基类。
    getDeclaredFields:获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
    getDeclaredField:获取某个类的所有成员变量指定变量名的字段,不包括基类。

    1.字段获取

            Class clazz = Class.forName("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

    2.字段的使用

        Class clazz = Class.forName("Reflection.Person");
        Person person = new Person("CYW");
            //获取私有字段的值
            Field field = clazz.getDeclaredField("Name");
            //由于是私有字段,需要使用setAccessible(true)
            field.setAccessible(true);
            Object val = field.get(person);
            System.out.println(val);
            //改变私有字段的值
            field.set(person, "ivan");
            System.out.println(person.getName());

    三、描述构造器Constructor
    先介绍下描述构造函数Constructor用到的方法,主要用到的还是4个:getConstructors、getDeclaredConstructors、getConstructor、getDeclaredConstructor。和前面Method、Field用的方法进行比较,类比思想,举一反三,我们也能大概了解这几个方法的使用。其实在编程中有好多体现哲学思想的地方,有正有反,有阴有阳,学会思考这样可以以点带面,触类旁通。
    getConstructors:获取对应类中public类型的构造函数,且只获取当前类的构造函数
    getConstructor:获取对应类中public指定参数类型的构造函数,且只获取当前类的构造函数
    getDeclaredConstructors:获取对应类中所有构造函数,包括私有构造函数,且只获取当前类的构造函数。

    getDeclaredConstructor:获取对应类中指定参数类型的方法,包括私有构造函数,且只获取当前类的方法。

            String className = "Reflection.Student";
            Class<Student> clazz = (Class<Student>) Class.forName(className);
    
            //指定成父类之后实际还是获取子类的构造函数
            Constructor<Person> [] constructors = 
                    (Constructor<Person>[]) Class.forName(className).getConstructors();
            
            for(Constructor<Person> constructor: constructors){
                System.out.println("getConstructors:"+constructor); 
            }
            
            Constructor<Student> []  constructorsa = 
                    (Constructor<Student>[]) Class.forName(className).getDeclaredConstructors();
            
            for(Constructor<Student> constructor: constructorsa){
                System.out.println("getDeclaredConstructors:"+constructor); 
            }
            
            
          //通过getConstructor获取公有构造函数
            Constructor<Student> constructor = clazz.getConstructor(String.class, String.class);
            System.out.println("getConstructor:"+constructor); 
            Student obj = constructor.newInstance("cyw", "123456");
            System.out.println(obj.getName());
            
            //通过getDeclaredConstructor获取私有构造函数
            constructor = clazz.getDeclaredConstructor(String.class);
            System.out.println("getDeclaredConstructor:"+constructor); 
            //对于私有构造函数在初始化之前要设置setAccessible(true)
            constructor.setAccessible(true);
            obj = constructor.newInstance("cyw");
            System.out.println(obj.getName());
    getConstructors:public Reflection.Student(java.lang.String,java.lang.String)
    getConstructors:public Reflection.Student()
    getDeclaredConstructors:public Reflection.Student(java.lang.String,java.lang.String)
    getDeclaredConstructors:private Reflection.Student(java.lang.String)
    getDeclaredConstructors:public Reflection.Student()
    getConstructor:public Reflection.Student(java.lang.String,java.lang.String)
    cyw
    getDeclaredConstructor:private Reflection.Student(java.lang.String)
    cyw

    四、描述注解Annotation
    描述注解主要用到getAnnotation(Class<A> annotationClass) 方法,它返回该元素的指定类型的注解,否则返回null。

            String className = "Reflection.Student";
            Class<Student> clazz = (Class<Student>) Class.forName(className);
            CustomDescriptions  customDescriptions =clazz.getAnnotation(CustomDescriptions.class);
            for(CustomDescription h: customDescriptions.value()){
                System.out.println("description:" + h.description());
            }
    description:学生
    description:人
  • 相关阅读:
    IP地址分类(A类 B类 C类 D类 E类)
    操作系统实六(页面置换算法之LRU)
    操作系统实验五(内存管理之动态分区分配(首次适应))
    操作系统实验四(内存管理之固定分区分配)
    CRT连接虚拟机中的linux系统(ubuntu)
    3种拨打电话的方式
    深度:ARC会导致的内存泄露
    iOS7.1Https企业证书发布方法
    iOS开发学习路线图
    iOS实例下载:使用腾讯的SDK将新浪微薄嵌入到应用中
  • 原文地址:https://www.cnblogs.com/5ishare/p/9452264.html
Copyright © 2020-2023  润新知