首页 > 技术文章 > Java -- 浅入Java反射机制

wjtaigwh 2017-03-29 17:19 原文

1,Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。

  Java 反射机制主要提供了以下功能:
  在运行时判断任意一个对象所属的类。
  在运行时构造任意一个类的对象。
  在运行时判断任意一个类所具有的成员变量和方法。
  在运行时调用任意一个对象的方法。

  在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
  Class类:代表一个类。
  Field 类:代表类的成员变量(成员变量也称为类的属性)。
  Method类:代表类的方法。
  Constructor 类:代表类的构造方法。
  Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

2,通过Class对象获取成员变量、成员方法、接口、超类、构造方法等。

  API中给我们提供了一下方法

getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

  下面就先从是用来说起吧

  • 通过对象获取完整的包名和类名
public class TestReflect{
    public static void main(String[] args){
        TestReflect testReflect = new TestReflect();
        System.out.println(testReflect.getClass().getName());
    }
}
  • 实例化class类对象
package com.qianmo.flowlayout.reflection;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Created by wangjitao on 2017/3/28 0028.
 * E-Mail:543441727@qq.com
 * Java反射机制的简单实现
 */

public class TestReflect{


    /**
     * @param args
     */
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
     

        Class<?> class1 = null;
        Class<?> class2 = null;
        Class<?> class3 = null;

        class1 = Class.forName("com.qianmo.flowlayout.reflection.TestReflect");
        class2 = new TestReflect().getClass();
        class3 =TestReflect.class;
        System.out.println("类名称:"+class1.getName());
        System.out.println("类名称:"+class2.getName());
        System.out.println("类名称:"+class3.getName());

    }
}
  • 获取对象父类和实现的接口
package com.qianmo.flowlayout.reflection;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Created by wangjitao on 2017/3/28 0028.
 * E-Mail:543441727@qq.com
 * Java反射机制的简单实现
 */

public class TestReflect{


    /**
     * @param args
     */
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
      Class<?> clazz =  Class.forName("com.qianmo.flowlayout.reflection.TestReflect");
        //获取父类
        Class<?> superClazz = clazz.getSuperclass();
        System.out.println("父类名称:"+superClazz.getName());
        //获取所有接口
        Class<?> intes[] = clazz.getInterfaces();
        for (int i = 0; i < intes.length; i++) {
            System.out.println("实现的接口有:"+intes[i].getName());
        }
    }
}
  • 通过反射得到一个类中的全部构造函数

  先创建User类

package com.qianmo.flowlayout.reflection;


/**
 * Created by wangjitao on 2017/3/29 0029.
 * E-Mail:543441727@qq.com
 */

public class User {
    private int age;
    private String name;

    public User() {
        super();

    }

    public User(int age) {
        super();
        this.age = age;
    }

    public User(String name) {
        super();
        this.name = name;
    }

    public User(int age, String name) {
        super();
        this.age = age;
        this.name = name;

    }

    public int getAge() {
        System.out.println("Java 反射机制 - 调用某个类的方法1.");
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("Java 反射机制 - 调用某个类的方法2.");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [age=" + age + ",name:" + name + "]";
    }
}

  在main方法中调用

package com.qianmo.flowlayout.reflection;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Created by wangjitao on 2017/3/28 0028.
 * E-Mail:543441727@qq.com
 * Java反射机制的简单实现
 */

public class TestReflect{


    /**
     * @param args
     */
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
      Class<?> class1 = null;
        class1 = Class.forName("com.qianmo.flowlayout.reflection.User");
        //第一种方法使用默认的构造方法
        User user_one = (User) class1.newInstance();
        user_one.setAge(20);
        user_one.setName("wangjitao");
        System.out.println(user_one);

        //第二种获取所有构造方法,使用构造函数赋值
        Constructor<?> cons[] =  class1.getConstructors();
        //查看每一个构造方法中所需要的参数
        for (int i = 0; i < cons.length; i++) {
            System.out.print("cons[" + i + "] (");
            Class<?> clazzs[] = cons[i].getParameterTypes();
            for (int j = 0; j <clazzs.length ; j++) {
                System.out.print(clazzs[j].getName()+",");
            }
            System.out.println(")");
        }

        //通过获取到的构造函数创建对象
        user_one = (User) cons[0].newInstance(24,"wangjitao04");
        System.out.println(user_one);
        user_one = (User) cons[1].newInstance("wangjitao04");
        System.out.println(user_one);
    }
}
  • 获取类中全部属性
    Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
        //获取本类中的全部属性
        Field[] field = clazz.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            //权限修饰符
            String priv = Modifier.toString(field[i].getModifiers());
            //属性类型
            Class<?> type = field[i].getType();
            System.out.println("修饰符:" + priv + ",属性类型:" + type.getName());

        }
        //获取实现的接口或者父类的属性
        Field[] fild1 = clazz.getFields();
        for (int i = 0; i <fild1.length ; i++) {
            int mo = fild1[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = fild1[i].getType();
            System.out.println(priv + " " + type.getName() + " " + fild1[i].getName() + ";");
        }
  • 获取类中的全部方法
    Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
        Method method[] = clazz.getMethods();
        for (int i = 0; i < method.length; i++) {
            Class<?> returnType = method[i].getReturnType();
            Class<?> para[] = method[i].getParameterTypes();
            int temp = method[i].getModifiers();
            System.out.println(method[i].getName() + "," + returnType.getName() + "," + Modifier.toString(temp));
            for (int j = 0; j < para.length; j++) {
                System.out.print(para[j].getName());
            }
        }
  • 通过反射调用类中的方法
        Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
        Method method = clazz.getMethod("getAge");
        method.invoke(clazz.newInstance());

        method = clazz.getMethod("setAge", int.class);
        method.invoke(clazz.newInstance(), 20);        
  • 通过反射操作类中的属性(包括私有属性)
        Class<?> clazz = Class.forName("com.qianmo.flowlayout.reflection.User");
        User user = (User) clazz.newInstance();
        Field field = clazz.getDeclaredField("age");
        field.setAccessible(true);
        field.set(user, 50);
        System.out.print(field.get(user));    

  通过以上的这些我们基本上可以在运行时候拿到一个类中成员变量、成员方法、接口、超类、构造方法等信息。

3,深入了解反射机制

  一般来说Java中使用Class.fromName()函数来生成Class对象,那我们来看看源码(这里只展示了主要的部分)

.......省略........
@CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        return forName(className, true, VMStack.getCallingClassLoader());
    }


 .......省略...........

  @CallerSensitive
    public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        if (loader == null) {
            loader = BootClassLoader.getInstance();
        }
        Class<?> result;
        try {
            result = classForName(name, initialize, loader);
        } catch (ClassNotFoundException e) {
            Throwable cause = e.getCause();
            if (cause instanceof LinkageError) {
                throw (LinkageError) cause;
            }
            throw e;
        }
        return result;
    }

/** Called after security checks have been made. */
    static native Class<?> classForName(String className, boolean shouldInitialize,
            ClassLoader classLoader) throws ClassNotFoundException;

  Class.forName(classname)方法,实际上是调用了Class类中的 Class.forName(classname, true, currentLoader)方法。参数:name - 所需类的完全限定名;initialize - 是否必须初始化类;loader - 用于加载类的类加载器。currentLoader则是通过调用ClassLoader.getCallerClassLoader()获取当前类加载器的。类要想使用,必须用类加载器加载,所以需要加载器。反射机制,不是每次都去重新反射,而是提供了cache,每次都会需要类加载器去自己的cache中查找,如果可以查到,则直接返回该类。 

  而java的类加载器也很有意思,分为一下四类

BootStrap Class Loader(引导类加载器);
Extensions Class Loader (扩展类加载器);
App ClassLoader(或System Class Loader);
Custom ClassLoader(用户自定义类加载器)

  类在加载的过程中,首先判断类是否被加载过,检测过程自底向上,首先从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。这里如果没有检测到则调用BootStrap ClassLoader加载器

    这幅图简单的说明了类加载器的类加载过程。先检查自己是否已经加载过该类,如果加载过,则直接返回该类,若没有则调用父类的loadClass方法,如果父类中没有,则执行findClass方法去尝试加载此类,也就是我们通常所理解的片面的"反射"了。这个过程主要通过ClassLoader.defineClass方法来完成。defineClass 方法将一个字节数组转换为 Class 类的实例(任何类的对象都是Class类的对象)。这种新定义的类的实例需要使用 Class.newInstance 来创建,而不能使用new来实例化。

推荐阅读