Java 反射详解

作者: 被称为L的男人 | 来源:发表于2016-03-23 15:52 被阅读6157次

    什么是反射?

    反射(Reflection)能够让运行于 JVM 中的程序检测和修改运行时的行为

    Class 类

    在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。虚拟机利用运行时信息选择相应的方法执行。可以通过专门的Java类访问这些信息,保存这些信息的类被称为Class。

    将Class类中的forName和newInstance配合使用,可以根据存储在字符串中的类名创建一个对象

    String s = "java.util.Date";
    Object m = Class.forName(s).newInstance();
    

    为什么需要反射?

    通过反射,我们能够

    • 在运行时检测对象的类型;
    • 动态构造某个类的对象;
    • 检测类的属性和方法;
    • 任意调用对象的方法;
    • 修改构造函数、方法、属性的可见性。

    JUnit

    JUnit通过反射来遍历包含 @Test 注解的方法,并在运行单元测试时调用它们。

    Web框架

    开发人员可以在配置文件中定义对各种接口和类的实现。通过反射机制,框架能够快速地动态初始化所需要的类。

    Spring框架使用如下的配置文件:

    <bean id="someID" class="com.programcreek.Foo">
        <property name="someField" value="someValue" />
    </bean>
    

    当Spring容器处理 bean 元素时,会使用Class.forName("com.programcreek.Foo")来初始化这个类,并再次使用反射获取 property 元素对应的setter方法,为对象的属性赋值。

    Servlet

    <servlet>
        <servlet-name>someServlet</servlet-name>
        <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
    <servlet>
    

    如何使用反射?

    反射的基本方法

    本着不重复造轮子的原则,API 详细参考自 这里,下面只做简单介绍。

    在java.lang.reflect包中有三个重要的类:

    • Field:描述类的域
    • Method:描述类的方法
    • Constructor:描述类的构造器

    对于public域(包括超类成员):

    • getFields
    • getMethods
    • getConstructors

    对于其它域(包括私有和受保护的成员,不包括超类成员):

    • gettDeclaredFields
    • gettDeclaredMethods
    • gettDeclaredConstructors

    下面介绍 Java 反射的使用,其中 Person 类及测试完整代码在本文最后。

    加载类

        // 加载类的3种方法
        Class clazz = Class.forName("com.yano.reflect.Person");
        Class clazz1 = new Person().getClass();
        Class class2 = Person.class;
    

    获取类的无参构造函数,并实例化类

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);
        Person p = (Person) c.newInstance(null);
    

    获取类的含参私有构造函数,并实例化类

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz
                .getDeclaredConstructor(new Class[] { String.class });
        // 由于构造函数是 private 的,所以需要屏蔽Java语言的访问检查
        c.setAccessible(true);
        Person p = (Person) c
                .newInstance(new Object[] { "I'm a reflect name!" });
    

    获取并调用类的无参方法

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);
        Person p = (Person) c.newInstance(null);
        Method method = clazz.getMethod("fun", null);
        method.invoke(p, null);
    

    获取并调用类的含参方法

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz.getConstructor(null);
        Person p = (Person) c.newInstance(null);
        Method method = clazz.getMethod("fun", new Class[] { String.class });
        method.invoke(p, new Object[] { "I'm a reflect method!" });
    

    获取类的字段

        Class clazz = Class.forName("com.yano.reflect.Person");
        Constructor c = clazz
                .getDeclaredConstructor(new Class[] { String.class });
        // 由于构造函数是 private 的,所以需要获取控制权限
        c.setAccessible(true);
        Person p = (Person) c
                .newInstance(new Object[] { "I'm a reflect name!" });
        Field f = clazz.getField("name");
        Object value = f.get(p);
        Class type = f.getType();
        System.out.println(type);
        if (type.equals(String.class)) {
            System.out.println((String) value);
        }
    

    完整代码

    Person 类

    package com.yano.reflect;
    
    public class Person {
    
        public String name = "default name";
        public int[] array = new int[10];
    
        public Person() {
            System.out.println(name);
            for (int i = 0; i < array.length; i++) {
                array[i] = i;
            }
        }
    
        private Person(String name) {
            this.name = name;
            System.out.println(name);
        }
    
        public void fun() {
            System.out.println("fun");
        }
    
        public void fun(String name) {
            System.out.println(name);
        }
    
    }
    

    test 类

    package com.yano.reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class test {
    
        /**
         * 反射:加载类的字节码
         * 
         * @throws SecurityException
         * @throws NoSuchMethodException
         */
        public static void main(String[] args) throws Exception {
    
            refGetClass();
    
            // 获取并调用无参构造函数
            refGetPublicConstructor();
    
            // 获取并调用私有的含参构造函数
            refGetPrivateConstructor();
    
            // 获取并调用无参方法 fun
            refGetMethodWithNoArg();
    
            // 获取并调用有参数方法 fun
            refGetMethodWithArg();
    
            // 获取类的字段
            refGetField();
        }
    
        private static void refGetField() throws Exception {
    
            Class clazz = Class.forName("com.yano.reflect.Person");
            Constructor c = clazz
                    .getDeclaredConstructor(new Class[] { String.class });
            // 由于构造函数是 private 的,所以需要获取控制权限
            c.setAccessible(true);
            Person p = (Person) c
                    .newInstance(new Object[] { "I'm a reflect name!" });
    
            Field f = clazz.getField("name");
            Object value = f.get(p);
            Class type = f.getType();
            System.out.println(type);
    
            if (type.equals(String.class)) {
                System.out.println((String) value);
            }
            System.out.println();
        }
    
        private static void refGetMethodWithArg() throws Exception {
    
            Class clazz = Class.forName("com.yano.reflect.Person");
            Constructor c = clazz.getConstructor(null);
            Person p = (Person) c.newInstance(null);
    
            Method method = clazz.getMethod("fun", new Class[] { String.class });
            method.invoke(p, new Object[] { "I'm a reflect method!" });
            System.out.println();
        }
    
        private static void refGetMethodWithNoArg() throws Exception {
    
            Class clazz = Class.forName("com.yano.reflect.Person");
            Constructor c = clazz.getConstructor(null);
            Person p = (Person) c.newInstance(null);
    
            Method method = clazz.getMethod("fun", null);
            method.invoke(p, null);
            System.out.println();
        }
    
        private static void refGetPrivateConstructor() throws Exception {
    
            Class clazz = Class.forName("com.yano.reflect.Person");
            Constructor c = clazz
                    .getDeclaredConstructor(new Class[] { String.class });
    
            // 由于构造函数是 private 的,所以需要屏蔽Java语言的访问检查
            c.setAccessible(true);
    
            Person p = (Person) c
                    .newInstance(new Object[] { "I'm a reflect name!" });
            System.out.println();
        }
    
        private static void refGetPublicConstructor() throws Exception {
    
            Class clazz = Class.forName("com.yano.reflect.Person");
            Constructor c = clazz.getConstructor(null);
    
            Person p = (Person) c.newInstance(null);
            System.out.println();
        }
    
        private static void refGetClass() throws ClassNotFoundException {
            // 加载类的3种方法
            Class clazz = Class.forName("com.yano.reflect.Person");
            Class clazz1 = new Person().getClass();
            Class class2 = Person.class;
            System.out.println();
        }
    
    }
    
    

    本文参考自:

    1. http://www.programcreek.com/2013/09/java-reflection-tutorial/
    2. http://www.importnew.com/9078.html
    3. 《Java 核心技术 卷 I》第 5 章

    相关文章

      网友评论

      本文标题:Java 反射详解

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