当前位置 博文首页 > JAVA_基础反射机制

    JAVA_基础反射机制

    作者:BeautifulGirl230 时间:2021-01-09 06:04

    Java反射机制概述

    Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。

    加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

    正常方式: 引入需要的包名称 → 通过new实例化对象 → 取得实例化对象
    反射方式: 通过实例化对象 → getClass()方法 → 得到完整的包名称

    Java反射机制提供的功能

    • 在运行时判断任意一个对象所属的类。
    • 在运行时构造任意一个类的对象。
    • 在运行时判断任意一个类所具有的成员变量和方法。
    • 在运行时获取泛型信息。
    • 在运行时调用任意一个对象的成员变量和方法。
    • 在运行时处理注解。
    • 生成动态代理。
    public class Person {
        private String name;
        public int age;
        public void show() {
            System.out.println("您好!世界");
        }
        private String showNation(String nation){
            System.out.println("我的国际是:" + nation);
            return nation;
        }
        private Person(String name) {
            this.name = name;
        }
    	.....
    }
    public void test2() throws Exception {
        Class clazz = Person.class;
        // 1.通过反射,创建Person类的对象
        Constructor cons = clazz.getConstructor(String.class, int.class);
        Object obj = cons.newInstance("Tom", 12);
        Person p = (Person) obj;
        System.out.println(p.toString());
        // 2.通过反射,调用指定的属性、方法、对象
        // 调属性
        Field age = clazz.getDeclaredField("age");
        age.set(p,10);
        System.out.println(p.toString());
        // 调方法
        Method method = clazz.getDeclaredMethod("show");
        method.invoke(p);
        // 通过反射是可以调用私有的属性、方法、构造器
        // 调用私有构造器
        Constructor cons1 = clazz.getDeclaredConstructor(String.class);
        cons1.setAccessible(true);
        Person p1 = (Person) cons1.newInstance("Jerry");
        System.out.println(p1);
        // 调用私有方法
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1,"Han");
        System.out.println(p1);
        // 调用私有方法
        Method method1 = clazz.getDeclaredMethod("showNation", String.class);
        method1.setAccessible(true);
        String invoke = (String) method1.invoke(p1, "中国");
        System.out.println(invoke);
    }
    

    java.lang.Class类的理解

    1. 类的加载过程:程序经过java.exe命令以后,会生成一个或多个字节码文件(.class),接着使用java.exe命令对字节码进行解释运行。相当与将某个字节码文件加载到内存中,此过程称为类的加载。加载到内存中的类,我们称之为运行时类,此运行时类,就作为Class的一个实例。
    2. Class的实例就是对应着一个运行时类。
    3. 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同方式来获取从运行时类。
    // 获取Class的实例的方法
    public void test3() throws ClassNotFoundException {
        // 方式一:调用运行时类的属性.class
        Class clazz1 = Person.class;
        // 方式二:通过运行时类的对象
        Person person = new Person();
        Class clazz2 = person.getClass();
        // 方法三:调用Class的静态方法forName(String classPath)
        Class clazz3 = Class.forName("com.tyt.java.Person");
        // 方式四:类的加载器 ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.tyt.java.Person");
        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
        System.out.println(clazz3 == clazz4);
    }
    

    Class实例可以是那些结构的说明:

    public void test5() {
        Class c1 = Object.class;
        Class c2 = Comparable.class;
        Class c3 = String[].class;
        Class c4 = int[][].class;
        Class c5 = ElementType.class;
        Class c6 = Override.class;
        Class c7 = int.class;
        Class c8 = void.class;
        Class c9 = Class.class;
    
        int[] a = new int[10];
        int[] b = new int[100];
        Class c10 = a.getClass();
        Class c11 = b.getClass();
        // 只要数组元素类型与维度一样,就是同一个Class
        System.out.println(c10 == c11);// true
    }
    

    使用Properties:用于读取配置文件。

    // 目录结构
    // |--module
    // |---stc
    // |----com.tyt.java
    // |-----PropertiesTest.java
    // |-----jdbc1.properties
    // |--jdbc.properties
    public void test2() {
        String user = null;
        String passwored = null;
        FileInputStream inputStream = null;
        try {
            Properties properties = new Properties();
            // 读取配置方式一:
            // inputStream = new FileInputStream("jdbc.properties");
            // properties.load(inputStream);
            // 读取配置方式二:使用ClassLoader
            // 配置文件默认识别为:当前module的src下
            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
            InputStream inputStream1 = classLoader.getResourceAsStream("jdbc1.properties");
            properties.load(inputStream1);
            user = properties.getProperty("user");
            passwored = properties.getProperty("passwored");
            System.out.println("user = " + user + ",passwored = " + passwored);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }