zoukankan      html  css  js  c++  java
  • 01、Java特性反射

    反射

    基本概念

    反射机制:将类的各个组成部分封装为其他对象,这就是反射机制。

    通俗来讲,反射就是来操作Java类的一种机制,通过反射可以操作Java中的字节码文件。

    反射的核心类是Class类,它是类的类模板,即该类是用来描述Java类的。

    描述的基本上就是一个类的组成部分:包名、类名、接口、父类、成员变量(Filed)、构造方法(Construct)、普通方法(Method)、注解(Annotation)等等。
    所以说,反射的操作基本上就是对这些类的元素进行操作。

    Java在计算机中会经历三个阶段,分别如下:

    Source源代码阶段:*.java文件会被编译成*.class字节码文件。

    Class对象阶段:*.class字节码文件会被类加载器装进内存,并将其封装成Class对象。

    RunTime运行阶段:创建对象的过程。

    其中,在Class对象阶段,Class对象将原字节码中所有成员变量封装成Field[],将构造函数封装成Construction[],将成员方法封装成Method[]。

    获取Class对象

    获取Class对象分别对应Java代码在计算机中的三个阶段:

    1、Source源代码阶段:多用于配置文件的读取和加载。

    Class.forName("全类名")。
    

    2、Class类对象阶段:多用于参数的传递。

    **.class
    

    3、Runtime运行阶段:多用于对象的获取字节码的方式

    xxx.getClass();
    

    注意:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。

    案例分析

    下面的案例演示三种Java字节码的获取方式:

    public class Main {
        public static void main(String[] args) throws ClassNotFoundException {
            // 方式一:Class.forName("全类名")
            Class clazz1 = Class.forName("com.legend.reflect.Person");
            System.out.println("clazz1 = " + clazz1);
    
            // 方式二:类名.class
            Class clazz2 = Person.class;
            System.out.println("clazz2 = " + clazz2);
    
            // 方式三:对象.getClass()
            Class clazz3 = new Person().getClass();
            System.out.println("clazz3 = " + clazz3);
    
            boolean isEquals = (clazz1 == clazz2) && (clazz2 == clazz3) ? true : false;
            System.out.println("clazz1 == clazz2 == clazz3:" + isEquals);
        }
    }
    

    输出结果如下所示:

    clazz1 = class com.legend.reflect.Person
    clazz2 = class com.legend.reflect.Person
    clazz3 = class com.legend.reflect.Person
    clazz1 == clazz2 == clazz3:true

    Class对象功能

    Class对象包含一个类的所有信息,这里只介绍主要的。

    (1)获取成员变量

    Field[] getFields() :获取所有public修饰的成员变量
    Field getField(String name)   获取指定名称的 public修饰的成员变量
    
    Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
    Field getDeclaredField(String name) 
    

    (2)获取构造函数

    Constructor<?>[] getConstructors()  
    Constructor<T> getConstructor(Class<?>... parameterTypes)  
    
    Constructor<?>[] getDeclaredConstructors()  
    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
    

    (3)获取成员方法

    Method[] getMethods()  
    Method getMethod(String name, Class<?>... parameterTypes)  
    
    Method[] getDeclaredMethods()  
    Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    

    (4)获取全类名

    String getName() 
    

    (5)获取类加载器

    ClassLoader	getClassLoader()
    

    Filed成员变量

    下面针对Person对象中的三种修饰符:private、protected和public三种类型的成员变量使用反射赋值。

    1、定义Person对象,并提供三种修饰符修饰的属性。

    public class Person {
        public String name;
        protected int age;
        private String address;
    
    	...get和set...
    }
    

    2、使用获取成员变量的方式进行反射,只能获取到public的成员变量。

    public class Main {
        public static void main(String[] args) throws NoSuchFieldException {
            Class personClass = Person.class;
            // 获取所有public修饰的成员变量
            Field[] fields = personClass.getFields();
            for (Field field : fields){
                System.out.println(field);
            }
        }
    }
    

    获取所有的变量,必须使用getDeclaredFields()方法来完成。

    public class Main {
        public static void main(String[] args) throws NoSuchFieldException {
            Class personClass = Person.class;
            Field[] fields = personClass.getDeclaredFields();
            for (Field field : fields){
                System.out.println(field);
            }
        }
    }
    

    注意:如果获取单个private或protected属性的值需要使用暴力反射来完成:setAccessible(true);

    Constructor构造函数

    通过反射的方式来创建对象,使用到的实体类如下:

    public class Person {
        private String name;
        private Integer age;
    
        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    	...get和set...
    }
    

    然后通过反射的方式来创建该对象:

    public class Main {
        public static void main(String[] args) throws Exception {
            Class personClass = Person.class;
            Constructor[] constructors = personClass.getConstructors();
            for (Constructor constructor : constructors){
                System.out.println(constructor);
            }
    
            // 获取有参的构造函数来创建对象
            Constructor constructor = personClass.getConstructor(String.class, Integer.class);
            Object legend = constructor.newInstance("Legend", 30);
            System.out.println(legend);
        }
    }
    

    如果要获取private修饰的构造函数,需要使用getDeclaredConstructor方法。

    Method方法对象

    通过反射调用对象中的方法,所用到的实例类如下:

    public class Person {
        private String name;
        private Integer age;
    
        public Person() {
        }
    	...get和set...
    
        public void eat(String food){
            System.out.println("eat..." + food);
        }
    }
    

    然后通过反射的方式来执行eat方法:

    public class Main {
        public static void main(String[] args) throws Exception {
            Class personClass = Person.class;
            // 获取所有public的方法
            Method[] methods = personClass.getMethods();
            for (Method method : methods){
                System.out.println(method);
            }
    
            // 执行字节码中的方法
            Object o = personClass.newInstance();
            Method method = personClass.getMethod("eat", String.class);
            method.invoke(o, "apple");
        }
    }
    

    反射的大致用法如上所示,还可以通过反射的方式去修改配置类并运行。

  • 相关阅读:
    C++类构造函数初始化列表(转)
    Linux可重入函数和线程安全的区别与联系(转)
    Splinter自动登录
    VBA添加下拉菜单
    批处理自动备份并生成日志文件
    VBA 格式化excel数据表 (数据分列)
    Python 调用outlook发送邮件(转 )
    Node.js 文件操作
    Node.js express模块 http服务
    将ejs模板文件的后缀换成html
  • 原文地址:https://www.cnblogs.com/pengjingya/p/14924718.html
Copyright © 2011-2022 走看看