美文网首页
初探反射机制

初探反射机制

作者: YoursBG | 来源:发表于2019-03-03 22:45 被阅读0次

    如果需要修改Test类对象的private testName属性,我们会怎么做呢?

    class Test {
        private String testName = "hello";
    
        public void setTestName(String name) {
            testName = name;
        }
    }
    

    通常我们可以提供一个public setTestName方法去修改testName值。
    当然,还可以使用本文的主角\color{red}{反射机制}达到修改testName值。

    反射机制常用方法之一:修改对象中private属性
    创建Test类对象test,test对象中有私有属性testName,testName初始值为hello。通过反射,将testName值修改成world。

    class Test {
        private String testName = "hello";
    
        public String getTestName() {
            return testName;
        }
    
        public static void main(String[] args) {
            try {
                Test test = new Test();
                System.out.println("testName:" + test.getTestName());//testName:hello
                Class<?> clazz = test.getClass();
                Field testNameField = clazz.getDeclaredField("testName");
                testNameField.setAccessible(true);
                testNameField.set(test, "world");
                System.out.println("testName:" + test.getTestName());//testName:world
            } catch (Exception e) {
            }
        }
    }
    

    通过例子我们感受到反射机制的作用,到底什么是反射,为什么需要反射,反射常用方法还有哪些。

    • 什么是反射?

    在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。
    用比喻来说,反射就是程序在运行的时候能够“观察”并且“修改”自己的行为。

    在Java中,
    反射能“观察”自己的具体表现就是:对于任意一个类,都能够知道这个类的所有方法和属性。
    反射能“修改”自己的具体表现就是:对于任意一个对象,都能够调用它的所有方法和改变所有的属性。

    • 为什么需要反射?

    1.反射使得设计更优雅易懂,例如日常使用的Spring框架,注解的形式就相当优雅易懂而且实用。
    关于“注解”详细介绍请点击//TODO

    @Controller
    class Test {
        public static void main(String[] args) {
            Class clazz = Test.class;
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
        }
    }
    

    2.Java中的动态代理、拦截器等,都是使用反射的“观察”和“修改”能力。

    通过反射的“观察”和“修改”能力,可以设计出更优雅易读而且实用的应用程序。为什么需要反射?因为在设计程序时,需要“观察”和“修改”的能力,而拥有这些能力的我们定义为反射。

    • 反射的常用方法

    获取Class对象的三种方式

    1.通过对象获取

    class Test {
        public static void main(String[] args) {
            Test test = new Test();
            Class clazz = test.getClass();
        }
    }
    

    2.通过类获取

    class Test {
        public static void main(String[] args) {
            Class clazz = Test.class;
        }
    }
    

    3.通过Class.forName获取

    class Test {
        public static void main(String[] args) {
            try {
                Class clazz = Class.forName("Test");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    
    获取类字段
    class Test {
        private String nickname;
    
        public static void main(String[] args) {
            Class clazz = Test.class;
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field);
            }
        }
    }
    
    获取类方法
    class Test {
        private String nickname;
    
        public String getNickname() {
            return nickname;
        }
    
        public static void main(String[] args) {
            Class clazz = Test.class;
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
        }
    }
    
    获取类构造器
    class Test {
        private String nickname;
    
        public Test(String nickname) {
            this.nickname = nickname;
        }
    
        public static void main(String[] args) {
            try {
                Class clazz = Test.class;
                Constructor constructor = clazz.getConstructor(String.class);
                Test test = (Test) constructor.newInstance("tom");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    更多反射的方法可以查看Class类的源码。查看源码时,例如Class.forName,里面调用forName0方法,会发现forName0方法是一个native方法,如何查看native方法的源码,JDK native源码查看

        @CallerSensitive
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    
        /** Called after security check for system loader access checks have been made. */
        private static native Class<?> forName0(String name, boolean initialize,
                                                ClassLoader loader,
                                                Class<?> caller)
            throws ClassNotFoundException;
    

    我们会发现,Java中,反射基本围绕着Class类展开,去实现反射的“观察”和“修改”能力,关于Class类文件的结构,参考Class类文件的结构。了解Class类文件的结构后,需要再去了解虚拟机类加载机制以及类加载器//TODO。
    而本文主要介绍反射机制基础概念,反射的意义及反射常用方法。
    想深入理解反射在JVM中的实现原理,除了需要阅读源码(包括阅读native方法源码),还需要理解Class类文件的结构,以及虚拟机类加载机制,做完这些工作,才算比较明白反射机制。

    深入理解反射机制//TODO

    相关文章

      网友评论

          本文标题:初探反射机制

          本文链接:https://www.haomeiwen.com/subject/vvgnyqtx.html