反射 学习笔记

713 阅读24分钟

反射

说说你对Java反射的理解?

答:Java 中的反射首先是能够获取到Java中要反射类的字节码, 获取字节码有三种方法:

1.Class.forName(className)

2.类名.class

3.this.getClass()。

然后将字节码中的方法,变量,构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们所使用。

Java反射机制是在运行状态中,对于任何一个类,都可以知道该类的所有属性和方法。对于任何一个类都可以访问该类的所有属性和方法。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

Java 反射主要提供以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  • 在运行时调用任意一个对象的方法

重点:是运行时而不是编译时

JVM

我们编写的.java文件在被编译器编译之后会生成.class文件,然后被JVM加载生成Class对象。Class对象是描述每个对象的说明书。

获取Class

反射的入口是Class。

Object.getClass()

在可以获得对象的情况下直接调用getClass()方法即可获得Class对象。

.class 标识

通过类的class属性获得Class对象。

Class.forName() 方法

当无法访问一个类的时候,例如Android系统把一些类加上了@hide注解,所示这些类就不会出现在 Android SDK中。可以通过类的全限定名来获取Class对象。

Class类型

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);

Class名字

可以根据需要选择适当的API进行类名的获取。

Class修饰符

通过调用Class.getModifiers()方法可以获取对应属性和方法的修饰符。

输出为private static

public class Modifier {

    /*
     * Bootstrapping protocol between java.lang and java.lang.reflect
     *  packages
     */
    static {
        sun.reflect.ReflectionFactory factory =
            AccessController.doPrivileged(
                new ReflectionFactory.GetReflectionFactoryAction());
        factory.setLangReflectAccess(new java.lang.reflect.ReflectAccess());
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code public} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code public} modifier; {@code false} otherwise.
     */
    public static boolean isPublic(int mod) {
        return (mod & PUBLIC) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code private} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code private} modifier; {@code false} otherwise.
     */
    public static boolean isPrivate(int mod) {
        return (mod & PRIVATE) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code protected} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code protected} modifier; {@code false} otherwise.
     */
    public static boolean isProtected(int mod) {
        return (mod & PROTECTED) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code static} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code static} modifier; {@code false} otherwise.
     */
    public static boolean isStatic(int mod) {
        return (mod & STATIC) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code final} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code final} modifier; {@code false} otherwise.
     */
    public static boolean isFinal(int mod) {
        return (mod & FINAL) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code synchronized} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code synchronized} modifier; {@code false} otherwise.
     */
    public static boolean isSynchronized(int mod) {
        return (mod & SYNCHRONIZED) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code volatile} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code volatile} modifier; {@code false} otherwise.
     */
    public static boolean isVolatile(int mod) {
        return (mod & VOLATILE) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code transient} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code transient} modifier; {@code false} otherwise.
     */
    public static boolean isTransient(int mod) {
        return (mod & TRANSIENT) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code native} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code native} modifier; {@code false} otherwise.
     */
    public static boolean isNative(int mod) {
        return (mod & NATIVE) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code interface} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code interface} modifier; {@code false} otherwise.
     */
    public static boolean isInterface(int mod) {
        return (mod & INTERFACE) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code abstract} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code abstract} modifier; {@code false} otherwise.
     */
    public static boolean isAbstract(int mod) {
        return (mod & ABSTRACT) != 0;
    }

    /**
     * Return {@code true} if the integer argument includes the
     * {@code strictfp} modifier, {@code false} otherwise.
     *
     * @param   mod a set of modifiers
     * @return {@code true} if {@code mod} includes the
     * {@code strictfp} modifier; {@code false} otherwise.
     */
    public static boolean isStrict(int mod) {
        return (mod & STRICT) != 0;
    }

    public static String toString(int mod) {
        StringBuilder sb = new StringBuilder();
        int len;

        if ((mod & PUBLIC) != 0)        sb.append("public ");
        if ((mod & PROTECTED) != 0)     sb.append("protected ");
        if ((mod & PRIVATE) != 0)       sb.append("private ");

        /* Canonical order */
        if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
        if ((mod & STATIC) != 0)        sb.append("static ");
        if ((mod & FINAL) != 0)         sb.append("final ");
        if ((mod & TRANSIENT) != 0)     sb.append("transient ");
        if ((mod & VOLATILE) != 0)      sb.append("volatile ");
        if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
        if ((mod & NATIVE) != 0)        sb.append("native ");
        if ((mod & STRICT) != 0)        sb.append("strictfp ");
        if ((mod & INTERFACE) != 0)     sb.append("interface ");

        if ((len = sb.length()) > 0)    /* trim trailing space */
            return sb.toString().substring(0, len-1);
        return "";
    }

    /*
     * Access modifier flag constants from tables 4.1, 4.4, 4.5, and 4.7 of
     * <cite>The Java&trade; Virtual Machine Specification</cite>
     */

    /**
     * The {@code int} value representing the {@code public}
     * modifier.
     */
    public static final int PUBLIC           = 0x00000001;

    /**
     * The {@code int} value representing the {@code private}
     * modifier.
     */
    public static final int PRIVATE          = 0x00000002;

    /**
     * The {@code int} value representing the {@code protected}
     * modifier.
     */
    public static final int PROTECTED        = 0x00000004;

    /**
     * The {@code int} value representing the {@code static}
     * modifier.
     */
    public static final int STATIC           = 0x00000008;

    /**
     * The {@code int} value representing the {@code final}
     * modifier.
     */
    public static final int FINAL            = 0x00000010;

    /**
     * The {@code int} value representing the {@code synchronized}
     * modifier.
     */
    public static final int SYNCHRONIZED     = 0x00000020;

    /**
     * The {@code int} value representing the {@code volatile}
     * modifier.
     */
    public static final int VOLATILE         = 0x00000040;

    /**
     * The {@code int} value representing the {@code transient}
     * modifier.
     */
    public static final int TRANSIENT        = 0x00000080;

    /**
     * The {@code int} value representing the {@code native}
     * modifier.
     */
    public static final int NATIVE           = 0x00000100;

    /**
     * The {@code int} value representing the {@code interface}
     * modifier.
     */
    public static final int INTERFACE        = 0x00000200;

    /**
     * The {@code int} value representing the {@code abstract}
     * modifier.
     */
    public static final int ABSTRACT         = 0x00000400;

    /**
     * The {@code int} value representing the {@code strictfp}
     * modifier.
     */
    public static final int STRICT           = 0x00000800;

    // Bits not (yet) exposed in the public API either because they
    // have different meanings for fields and methods and there is no
    // way to distinguish between the two in this class, or because
    // they are not Java programming language keywords
    static final int BRIDGE    = 0x00000040;
    static final int VARARGS   = 0x00000080;
    static final int SYNTHETIC = 0x00001000;
    static final int ANNOTATION  = 0x00002000;
    static final int ENUM      = 0x00004000;
    static final int MANDATED  = 0x00008000;
    static boolean isSynthetic(int mod) {
      return (mod & SYNTHETIC) != 0;
    }

    static boolean isMandated(int mod) {
      return (mod & MANDATED) != 0;
    }

    // Note on the FOO_MODIFIERS fields and fooModifiers() methods:
    // the sets of modifiers are not guaranteed to be constants
    // across time and Java SE releases. Therefore, it would not be
    // appropriate to expose an external interface to this information
    // that would allow the values to be treated as Java-level
    // constants since the values could be constant folded and updates
    // to the sets of modifiers missed. Thus, the fooModifiers()
    // methods return an unchanging values for a given release, but a
    // value that can potentially change over time.

    /**
     * The Java source modifiers that can be applied to a class.
     * @jls 8.1.1 Class Modifiers
     */
    private static final int CLASS_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.FINAL   |
        Modifier.STRICT;

    /**
     * The Java source modifiers that can be applied to an interface.
     * @jls 9.1.1 Interface Modifiers
     */
    private static final int INTERFACE_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.STRICT;


    /**
     * The Java source modifiers that can be applied to a constructor.
     * @jls 8.8.3 Constructor Modifiers
     */
    private static final int CONSTRUCTOR_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE;

    /**
     * The Java source modifiers that can be applied to a method.
     * @jls8.4.3  Method Modifiers
     */
    private static final int METHOD_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.FINAL   |
        Modifier.SYNCHRONIZED   | Modifier.NATIVE       | Modifier.STRICT;

    /**
     * The Java source modifiers that can be applied to a field.
     * @jls 8.3.1  Field Modifiers
     */
    private static final int FIELD_MODIFIERS =
        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
        Modifier.STATIC         | Modifier.FINAL        | Modifier.TRANSIENT |
        Modifier.VOLATILE;

    /**
     * The Java source modifiers that can be applied to a method or constructor parameter.
     * @jls 8.4.1 Formal Parameters
     */
    private static final int PARAMETER_MODIFIERS =
        Modifier.FINAL;

    /**
     *
     */
    static final int ACCESS_MODIFIERS =
        Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a class.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a class.
     *
     * @jls 8.1.1 Class Modifiers
     * @since 1.7
     */
    public static int classModifiers() {
        return CLASS_MODIFIERS;
    }

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to an interface.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to an interface.
     *
     * @jls 9.1.1 Interface Modifiers
     * @since 1.7
     */
    public static int interfaceModifiers() {
        return INTERFACE_MODIFIERS;
    }

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a constructor.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a constructor.
     *
     * @jls 8.8.3 Constructor Modifiers
     * @since 1.7
     */
    public static int constructorModifiers() {
        return CONSTRUCTOR_MODIFIERS;
    }

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a method.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a method.
     *
     * @jls 8.4.3 Method Modifiers
     * @since 1.7
     */
    public static int methodModifiers() {
        return METHOD_MODIFIERS;
    }

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a field.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a field.
     *
     * @jls 8.3.1 Field Modifiers
     * @since 1.7
     */
    public static int fieldModifiers() {
        return FIELD_MODIFIERS;
    }

    /**
     * Return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a parameter.
     * @return an {@code int} value OR-ing together the source language
     * modifiers that can be applied to a parameter.
     *
     * @jls 8.4.1 Formal Parameters
     * @since 1.8
     */
    public static int parameterModifiers() {
        return PARAMETER_MODIFIERS;
    }
}

Modifier 还提供了一系列的静态工具方法用来对修饰符进行操作。

获取 Class 的成员

获取 Filed

//获取所有的属性,但不包括从父类继承下来的属性
public Field[] getDeclaredFields() throws SecurityException {}

//获取自身的所有的 public 属性,包括从父类继承下来的。
public Field[] getFields() throws SecurityException {}

获取 Method

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

public Method getMethod(String name, Class<?>... parameterTypes)

public Method[] getDeclaredMethods() throws SecurityException

public Method getMethod(String name, Class<?>... parameterTypes) 

获取 Constructor

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

public Constructor<T> getConstructor(Class<?>... parameterTypes)

public Constructor<?>[] getDeclaredConstructors() throws SecurityException 

public Constructor<?>[] getConstructors() throws SecurityException 

需要注意的是,Constructor 不能从父类继承。

操作Field

获取Field类型

//能够获取到泛型类型
public Type getGenericType() {}
//基础类型
public Class<?> getType() {}

获取Field类型修饰符

public int getModifiers() {}

读取与设置Field内容

读取内容

public Object get(Object obj);

public int getInt(Object obj);

public long getLong(Object obj) throws IllegalArgumentException, IllegalAccessException;

public float getFloat(Object obj) throws IllegalArgumentException, IllegalAccessException;

public short getShort(Object obj) throws IllegalArgumentException, IllegalAccessException;

public double getDouble(Object obj) throws IllegalArgumentException, IllegalAccessException;

public char getChar(Object obj) throws IllegalArgumentException, IllegalAccessException;

public byte getByte(Object obj) throws IllegalArgumentException, IllegalAccessException;

public boolean getBoolean(Object obj) throws IllegalArgumentException, IllegalAccessException

设置内容

public void set(Object obj, Object value);

public void getInt(Object obj,int value);

public void getLong(Object obj,long value) throws IllegalArgumentException, IllegalAccessException;

public void getFloat(Object obj,float value) throws IllegalArgumentException, IllegalAccessException;

public void getShort(Object obj,short value) throws IllegalArgumentException, IllegalAccessException;

public void getDouble(Object obj,double value) throws IllegalArgumentException, IllegalAccessException;

public void getChar(Object obj,char value) throws IllegalArgumentException, IllegalAccessException;

public void getByte(Object obj,byte b) throws IllegalArgumentException, IllegalAccessException;

public void getBoolean(Object obj,boolean b) throws IllegalArgumentException, IllegalAccessException

Class 本身不对成员进行储存,它只提供检索,所以需要用Field、Method、Constructor 对象来承载这些成员,所以,针对成员的操作时,一般需要为成员指定类的实例引用。

操作Method

获取Method类型

public String getName() {}

获取Method方法参数

public Parameter[] getParameters() {}

Parameter.java

// 获取参数名字
public String getName() {}

// 获取参数类型
public Class<?> getType() {}

// 获取参数的修饰符
public int getModifiers() {}

// 获取所有的参数类型
public Class<?>[] getParameterTypes() {}

// 获取所有的参数类型,包括泛型
public Type[] getGenericParameterTypes() {}

获取Method返回值类型

// 获取返回值类型
public Class<?> getReturnType() {}

// 获取返回值类型包括泛型
public Type getGenericReturnType() {}

获取Method修饰符

public int getModifiers() {}

获取Method异常类型

public Class<?>[] getExceptionTypes() {}

public Type[] getGenericExceptionTypes() {}

执行Method方法

public Object invoke(Object obj, Object... args) {}

Method 调用 invoke() 的时候,存在许多细节:

1.invoke() 方法中第一个参数 Object 实质上是 Method 所依附的 Class 对应的类的实例,如果这个方法是一个静态方法,那么 ojb 为 null,后面的可变参数 Object 对应的自然就是参数。

2.invoke() 返回的对象是 Object,所以实际上执行的时候要进行强制转换。

3.在对 Method 调用 invoke() 的时候,如果方法本身会抛出异常,那么这个异常就会经过包装,由 Method 统一抛出 InvocationTargetException。而通过 InvocationTargetException.getCause() 可以获取真正的异常。

通过反射运行配置文件内容

public class Student {
	public void show(){
		System.out.println("is show()");
	}
}

配置文件以txt文件为例子(pro.txt):

className = cn.fanshe.Student
methodName = show
/*
 * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
 * 我们只需要将新类发送给客户端,并修改配置文件即可
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		//通过反射获取Class对象
		Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"
		//2获取show()方法
		Method m = stuClass.getMethod(getValue("methodName"));//show
		//3.调用show()方法
		m.invoke(stuClass.getConstructor().newInstance());
		
	}
	
	//此方法接收一个key,在配置文件中获取相应的value
	public static String getValue(String key) throws IOException{
		Properties pro = new Properties();//获取配置文件的对象
		FileReader in = new FileReader("pro.txt");//获取输入流
		pro.load(in);//将流加载到配置文件对象中
		in.close();
		return pro.getProperty(key);//返回根据key获取的value值
	}
}

当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动

public class Student2 {
	public void show2(){
		System.out.println("is show2()");
	}
}

配置文件更改为:

className = cn.fanshe.Student2
methodName = show2

通过反射越过泛型检查 泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的。

/*
 * 通过反射越过泛型检查
 * 
 * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
 */
public class Demo {
	public static void main(String[] args) throws Exception{
		ArrayList<String> strList = new ArrayList<>();
		strList.add("aaa");
		strList.add("bbb");
		
	//	strList.add(100);
		//获取ArrayList的Class对象,反向的调用add()方法,添加数据
		Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
		//获取add()方法
		Method m = listClass.getMethod("add", Object.class);
		//调用add()方法
		m.invoke(strList, 100);
		
		//遍历集合
		for(Object obj : strList){
			System.out.println(obj);
		}
	}
}

浅析invoke过程

@CallerSensitive
public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}
  1. 权限检查

invoke方法会首先检查AccessibleObject的override属性的值。AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

override的值默认是false,表示需要权限调用规则,调用方法时需要检查权限;我们也可以用setAccessible方法设置为true,若override的值为true,表示忽略权限规则,调用方法时无需检查权限(也就是说可以调用任意的private方法,违反了封装)。 如果override属性为默认值false,则进行进一步的权限检查:

(1)首先用Reflection.quickCheckMemberAccess(clazz, modifiers)方法检查方法是否为public,如果是的话跳出本步;如果不是public方法,那么用Reflection.getCallerClass()方法获取调用这个方法的Class对象,这是一个native方法:

@CallerSensitive
public static native Class<?> getCallerClass();

在OpenJDK的源码中找到此方法的JNI入口(Reflection.c):

JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
(JNIEnv *env, jclass unused)
{
    return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
}

其中JVM_GetCallerClass的源码如下,有兴趣的可以研究一下(位于jvm.cpp):

JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth))
  JVMWrapper("JVM_GetCallerClass");
  // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation; or
  // sun.reflect.Reflection.getCallerClass with a depth parameter is provided
  // temporarily for existing code to use until a replacement API is defined.
  if (SystemDictionary::reflect_CallerSensitive_klass() == NULL || depth != JVM_CALLER_DEPTH) {
    Klass* k = thread->security_get_caller_class(depth);
    return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror());
  }
  // Getting the class of the caller frame.
  //
  // The call stack at this point looks something like this:
  //
  // [0] [ @CallerSensitive public sun.reflect.Reflection.getCallerClass ]
  // [1] [ @CallerSensitive API.method                                   ]
  // [.] [ (skipped intermediate frames)                                 ]
  // [n] [ caller                                                        ]
  vframeStream vfst(thread);
  // Cf. LibraryCallKit::inline_native_Reflection_getCallerClass
  for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) {
    Method* m = vfst.method();
    assert(m != NULL, "sanity");
    switch (n) {
    case 0:
      // This must only be called from Reflection.getCallerClass
      if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) {
        THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetCallerClass must only be called from Reflection.getCallerClass");
      }
      // fall-through
    case 1:
      // Frame 0 and 1 must be caller sensitive.
      if (!m->caller_sensitive()) {
        THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), err_msg("CallerSensitive annotation expected at frame %d", n));
      }
      break;
    default:
      if (!m->is_ignored_by_security_stack_walk()) {
        // We have reached the desired frame; return the holder class.
        return (jclass) JNIHandles::make_local(env, m->method_holder()->java_mirror());
      }
      break;
    }
  }
  return NULL;
JVM_END

获取了这个Class对象caller后用checkAccess方法做一次快速的权限校验,其实现为:

volatile Object securityCheckCache;
    void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
        throws IllegalAccessException
    {
        if (caller == clazz) {  // 快速校验
            return;             // 权限通过校验
        }
        Object cache = securityCheckCache;  // read volatile
        Class<?> targetClass = clazz;
        if (obj != null
            && Modifier.isProtected(modifiers)
            && ((targetClass = obj.getClass()) != clazz)) {
            // Must match a 2-list of { caller, targetClass }.
            if (cache instanceof Class[]) {
                Class<?>[] cache2 = (Class<?>[]) cache;
                if (cache2[1] == targetClass &&
                    cache2[0] == caller) {
                    return;     // ACCESS IS OK
                }
                // (Test cache[1] first since range check for [1]
                // subsumes range check for [0].)
            }
        } else if (cache == caller) {
            // Non-protected case (or obj.class == this.clazz).
            return;             // ACCESS IS OK
        }
        // If no return, fall through to the slow path.
        slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
    }

首先先执行一次快速校验,一旦调用方法的Class正确则权限检查通过。 若未通过,则创建一个缓存,中间再进行一堆检查(比如检验是否为protected属性)。 如果上面的所有权限检查都未通过,那么将执行更详细的检查,其实现为:

// Keep all this slow stuff out of line:
void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
                           Class<?> targetClass)
    throws IllegalAccessException
{
    Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
    // Success: Update the cache.
    Object cache = ((targetClass == clazz)
                    ? caller
                    : new Class<?>[] { caller, targetClass });
    // Note:  The two cache elements are not volatile,
    // but they are effectively final.  The Java memory model
    // guarantees that the initializing stores for the cache
    // elements will occur before the volatile write.
    securityCheckCache = cache;         // write volatile
}

大体意思就是,用Reflection.ensureMemberAccess方法继续检查权限,若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这是一种简单的缓存机制。由于JMM的happens-before规则能够保证缓存初始化能够在写缓存之前发生,因此两个cache不需要声明为volatile。 到这里,前期的权限检查工作就结束了。如果没有通过检查则会抛出异常,如果通过了检查则会到下一步。

  1. 调用MethodAccessor的invoke方法

Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。 首先要了解Method对象的基本构成,每个Java方法有且只有一个Method对象作为root,它相当于根对象,对用户不可见。当我们创建Method对象时,我们代码中获得的Method对象都相当于它的副本(或引用)。root对象持有一个MethodAccessor对象,所以所有获取到的Method对象都共享这一个MethodAccessor对象,因此必须保证它在内存中的可见性。root对象其声明及注释为:

private volatile MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Method  root;

那么MethodAccessor到底是个啥玩意呢?

/** This interface provides the declaration for
    java.lang.reflect.Method.invoke(). Each Method object is
    configured with a (possibly dynamically-generated) class which
    implements this interface.
*/
public interface MethodAccessor {
    /** Matches specification in {@link java.lang.reflect.Method} */
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException;
}

可以看到MethodAccessor是一个接口,定义了invoke方法。分析其Usage可得它的具体实现类有:

  • sun.reflect.DelegatingMethodAccessorImpl
  • sun.reflect.MethodAccessorImpl
  • sun.reflect.NativeMethodAccessorImpl

第一次调用一个Java方法对应的Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没有创建;等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()完成反射调用:

// NOTE that there is no synchronization used here. It is correct
// (though not efficient) to generate more than one MethodAccessor
// for a given Method. However, avoiding synchronization will
// probably make the implementation more scalable.
private MethodAccessor acquireMethodAccessor() {
    // First check to see if one has been created yet, and take it
    // if so
    MethodAccessor tmp = null;
    if (root != null) tmp = root.getMethodAccessor();
    if (tmp != null) {
        methodAccessor = tmp;
    } else {
        // Otherwise fabricate one and propagate it up to the root
        tmp = reflectionFactory.newMethodAccessor(this);
        setMethodAccessor(tmp);
    }
    return tmp;
}

可以看到methodAccessor实例由reflectionFactory对象操控生成,它在AccessibleObject下的声明如下:

// Reflection factory used by subclasses for creating field,
// method, and constructor accessors. Note that this is called
// very early in the bootstrapping process.
static final ReflectionFactory reflectionFactory =
    AccessController.doPrivileged(
        new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());

再研究一下sun.reflect.ReflectionFactory类的源码:

public class ReflectionFactory {
    private static boolean initted = false;
    private static Permission reflectionFactoryAccessPerm
        = new RuntimePermission("reflectionFactoryAccess");
    private static ReflectionFactory soleInstance = new ReflectionFactory();
    // Provides access to package-private mechanisms in java.lang.reflect
    private static volatile LangReflectAccess langReflectAccess;
    // 这里设计得非常巧妙
    // "Inflation" mechanism. Loading bytecodes to implement
    // Method.invoke() and Constructor.newInstance() currently costs
    // 3-4x more than an invocation via native code for the first
    // invocation (though subsequent invocations have been benchmarked
    // to be over 20x faster). Unfortunately this cost increases
    // startup time for certain applications that use reflection
    // intensively (but only once per class) to bootstrap themselves.
    // To avoid this penalty we reuse the existing JVM entry points
    // for the first few invocations of Methods and Constructors and
    // then switch to the bytecode-based implementations.
    //
    // Package-private to be accessible to NativeMethodAccessorImpl
    // and NativeConstructorAccessorImpl
    private static boolean noInflation        = false;
    private static int     inflationThreshold = 15;
    //......
	//这是生成MethodAccessor的方法
    public MethodAccessor newMethodAccessor(Method method) {
        checkInitted();
        if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
            return new MethodAccessorGenerator().
                generateMethod(method.getDeclaringClass(),
                               method.getName(),
                               method.getParameterTypes(),
                               method.getReturnType(),
                               method.getExceptionTypes(),
                               method.getModifiers());
        } else {
            NativeMethodAccessorImpl acc =
                new NativeMethodAccessorImpl(method);
            DelegatingMethodAccessorImpl res =
                new DelegatingMethodAccessorImpl(acc);
            acc.setParent(res);
            return res;
        }
    }
    //......
    /** We have to defer full initialization of this class until after
    the static initializer is run since java.lang.reflect.Method's
    static initializer (more properly, that for
    java.lang.reflect.AccessibleObject) causes this class's to be
    run, before the system properties are set up. */
    private static void checkInitted() {
        if (initted) return;
        AccessController.doPrivileged(
            new PrivilegedAction<Void>() {
                public Void run() {
                    // Tests to ensure the system properties table is fully
                    // initialized. This is needed because reflection code is
                    // called very early in the initialization process (before
                    // command-line arguments have been parsed and therefore
                    // these user-settable properties installed.) We assume that
                    // if System.out is non-null then the System class has been
                    // fully initialized and that the bulk of the startup code
                    // has been run.
                    if (System.out == null) {
                        // java.lang.System not yet fully initialized
                        return null;
                    }
                    String val = System.getProperty("sun.reflect.noInflation");
                    if (val != null && val.equals("true")) {
                        noInflation = true;
                    }
                    val = System.getProperty("sun.reflect.inflationThreshold");
                    if (val != null) {
                        try {
                            inflationThreshold = Integer.parseInt(val);
                        } catch (NumberFormatException e) {
                            throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e);
                        }
                    }
                    initted = true;
                    return null;
                }
            });
    }
}

观察前面的声明部分的注释,我们可以发现一些有趣的东西。就像注释里说的,实际的MethodAccessor实现有两个版本,一个是Java版本,一个是native版本,两者各有特点。初次启动时Method.invoke()和Constructor.newInstance()方法采用native方法要比Java方法快3-4倍,而启动后native方法又要消耗额外的性能而慢于Java方法。也就是说,Java实现的版本在初始化时需要较多时间,但长久来说性能较好;native版本正好相反,启动时相对较快,但运行时间长了之后速度就比不过Java版了。这是HotSpot的优化方式带来的性能特性,同时也是许多虚拟机的共同点:跨越native边界会对优化有阻碍作用,它就像个黑箱一样让虚拟机难以分析也将其内联,于是运行时间长了之后反而是托管版本的代码更快些。

为了尽可能地减少性能损耗,HotSpot JDK采用“inflation”的技巧:让Java方法在被反射调用时,开头若干次使用native版,等反射调用次数超过阈值时则生成一个专用的MethodAccessor实现类,生成其中的invoke()方法的字节码,以后对该Java方法的反射调用就会使用Java版本。 这项优化是从JDK 1.4开始的。

研究ReflectionFactory.newMethodAccessor()生产MethodAccessor对象的逻辑,一开始(native版)会生产NativeMethodAccessorImpl和DelegatingMethodAccessorImpl两个对象。 DelegatingMethodAccessorImpl的源码如下:

/** Delegates its invocation to another MethodAccessorImpl and can
    change its delegate at run time. */
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
    private MethodAccessorImpl delegate;
    DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
        setDelegate(delegate);
    }
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        return delegate.invoke(obj, args);
    }
    void setDelegate(MethodAccessorImpl delegate) {
        this.delegate = delegate;
    }
}

它其实是一个中间层,方便在native版与Java版的MethodAccessor之间进行切换。 然后下面就是native版MethodAccessor的Java方面的声明: sun.reflect.NativeMethodAccessorImpl:

/** Used only for the first few invocations of a Method; afterward,
    switches to bytecode-based implementation */
class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;
    NativeMethodAccessorImpl(Method method) {
        this.method = method;
    }
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        // We can't inflate methods belonging to vm-anonymous classes because
        // that kind of class can't be referred to by name, hence can't be
        // found from the generated bytecode.
        if (++numInvocations > ReflectionFactory.inflationThreshold()
                && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
            MethodAccessorImpl acc = (MethodAccessorImpl)
                new MethodAccessorGenerator().
                    generateMethod(method.getDeclaringClass(),
                                   method.getName(),
                                   method.getParameterTypes(),
                                   method.getReturnType(),
                                   method.getExceptionTypes(),
                                   method.getModifiers());
            parent.setDelegate(acc);
        }
        return invoke0(method, obj, args);
    }
    void setParent(DelegatingMethodAccessorImpl parent) {
        this.parent = parent;
    }
    private static native Object invoke0(Method m, Object obj, Object[] args);
}

每次NativeMethodAccessorImpl.invoke()方法被调用时,程序调用计数器都会增加1,看看是否超过阈值;一旦超过,则调用MethodAccessorGenerator.generateMethod()来生成Java版的MethodAccessor的实现类,并且改变DelegatingMethodAccessorImpl所引用的MethodAccessor为Java版。后续经由DelegatingMethodAccessorImpl.invoke()调用到的就是Java版的实现了。 到这里,我们已经追寻到native版的invoke方法在Java一侧声明的最底层 - invoke0了,下面我们将深入到HotSpot JVM中去研究其具体实现。

invoke0方法是一个native方法,它在HotSpot JVM里调用JVM_InvokeMethod函数:

JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0
(JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
{
    return JVM_InvokeMethod(env, m, obj, args);
}

openjdk/hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
  JVMWrapper("JVM_InvokeMethod");
  Handle method_handle;
  if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
    method_handle = Handle(THREAD, JNIHandles::resolve(method));
    Handle receiver(THREAD, JNIHandles::resolve(obj));
    objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
    oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
    jobject res = JNIHandles::make_local(env, result);
    if (JvmtiExport::should_post_vm_object_alloc()) {
      oop ret_type = java_lang_reflect_Method::return_type(method_handle());
      assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
      if (java_lang_Class::is_primitive(ret_type)) {
        // Only for primitive type vm allocates memory for java object.
        // See box() method.
        JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
      }
    }
    return res;
  } else {
    THROW_0(vmSymbols::java_lang_StackOverflowError());
  }
JVM_END

其关键部分为Reflection::invoke_method: openjdk/hotspot/src/share/vm/runtime/reflection.cpp

oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
  oop mirror             = java_lang_reflect_Method::clazz(method_mirror);
  int slot               = java_lang_reflect_Method::slot(method_mirror);
  bool override          = java_lang_reflect_Method::override(method_mirror) != 0;
  objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
  oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
  BasicType rtype;
  if (java_lang_Class::is_primitive(return_type_mirror)) {
    rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
  } else {
    rtype = T_OBJECT;
  }
  instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror));
  Method* m = klass->method_with_idnum(slot);
  if (m == NULL) {
    THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
  }
  methodHandle method(THREAD, m);
  return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
}

Java版MethodAccessor的生成使用MethodAccessorGenerator实现,由于代码太长,这里就不贴代码了,只贴一下开头的注释:

/** Generator for sun.reflect.MethodAccessor and
    sun.reflect.ConstructorAccessor objects using bytecodes to
    implement reflection. A java.lang.reflect.Method or
    java.lang.reflect.Constructor object can delegate its invoke or
    newInstance method to an accessor using native code or to one
    generated by this class. (Methods and Constructors were merged
    together in this class to ensure maximum code sharing.) */

这里运用了asm动态生成字节码技术(sun.reflect.ClassFileAssembler)。

MagicAccessorImpl是什么?

原本Java的安全机制使得不同类之间不是任意信息都可见,但JDK里面专门设了个MagicAccessorImpl标记类开了个后门来允许不同类之间信息可以互相访问(由JVM管理):

/** <P> MagicAccessorImpl (named for parity with FieldAccessorImpl and
    others, not because it actually implements an interface) is a
    marker class in the hierarchy. All subclasses of this class are
    "magically" granted access by the VM to otherwise inaccessible
    fields and methods of other classes. It is used to hold the code
    for dynamically-generated FieldAccessorImpl and MethodAccessorImpl
    subclasses. (Use of the word "unsafe" was avoided in this class's
    name to avoid confusion with {@link sun.misc.Unsafe}.) </P>
    <P> The bug fix for 4486457 also necessitated disabling
    verification for this class and all subclasses, as opposed to just
    SerializationConstructorAccessorImpl and subclasses, to avoid
    having to indicate to the VM which of these dynamically-generated
    stub classes were known to be able to pass the verifier. </P>
    <P> Do not change the name of this class without also changing the
    VM's code. </P> */
class MagicAccessorImpl {
}

@CallerSensitive注解又是什么?

/**
 * A method annotated @CallerSensitive is sensitive to its calling class,
 * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
 * or via some equivalent.
 *
 * @author John R. Rose
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface CallerSensitive {
}

简而言之,用@CallerSensitive注解修饰的方法从一开始就知道具体调用它的对象,这样就不用再经过一系列的检查才能确定具体调用它的对象了。它实际上是调用sun.reflect.Reflection.getCallerClass方法。

Reflection类位于调用栈中的0帧位置,sun.reflect.Reflection.getCallerClass()方法返回调用栈中从0帧开始的第x帧中的类实例。该方法提供的机制可用于确定调用者类,从而实现“感知调用者(Caller Sensitive)”的行为,即允许应用程序根据调用类或调用栈中的其它类来改变其自身的行为。

操作Method方法

public class test1 {
	public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
	        Class<?> c = methodClass.class;
	        Object object = c.newInstance();
	        Method[] methods = c.getMethods();
	        Method[] declaredMethods = c.getDeclaredMethods();
	        //获取methodClass类的add方法
	        Method method = c.getMethod("add", int.class, int.class);
	        //getMethods()方法获取的所有方法
	        System.out.println("getMethods获取的方法:");
	        for(Method m:methods)
	            System.out.println(m);
	        //getDeclaredMethods()方法获取的所有方法
	        System.out.println("getDeclaredMethods获取的方法:");
	        for(Method m:declaredMethods)
	            System.out.println(m);
	    }
    }
class methodClass {
    public final int fuck = 3;
    public int add(int a,int b) {
        return a+b;
    }
    public int sub(int a,int b) {
        return a+b;
    }
}
getMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
getDeclaredMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)

操作Constructor

在 Java 反射机制中有两种方法可以用来创建类的对象实例:Class.newInstance() 和 Constructor.newInstance()。

1.Class.newInstance() 只能调用无参的构造方法,而 Constructor.newInstance() 则可以调用任意的构造方法。

2.Class.newInstance() 通过构造方法直接抛出异常,而 Constructor.newInstance() 会把抛出来的异常包装到 InvocationTargetException 里面去,这个和 Method 行为一致。

3.Class.newInstance() 要求构造方法能够被访问,而 Constructor.newInstance() 却能够访问 private 修饰的构造器。

使用Class对象的newInstance()方法来创建Class对象对应类的实例。

Class<?> c = String.class;
Object str = c.newInstance();

先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);

操作数组

动态创建数组

Array.newInstance()

public static Object newInstance(Class<?> componentType, int... dimensions)
        throws IllegalArgumentException, NegativeArraySizeException {}

第一个参数是数组内的元素类型,第一个参数是可变参数,表示的是相应维度的数组长度限制。

Array.newInstance(String.class,2,3);表示创建一个String[2][3]的数组

读取与赋值数组

public static void set(Object array,
                       int index,
                       Object value)
                throws IllegalArgumentException,
                       ArrayIndexOutOfBoundsException;

public static Object get(Object array,
                         int index)
                  throws IllegalArgumentException,
                         ArrayIndexOutOfBoundsException;

操作Enum

// 用来判定 Class 对象是不是枚举类型
Class.isEnum()

// 获取所有的枚举常量
Class.getEnumConstants()

// 判断一个 Field 是不是枚举常量
java.lang.reflect.Field.isEnumConstant()

获取与设定枚举

因为等同于 Class,所以枚举的获取与设定就可以通过 Field 中的 get() 和 set() 方法。

需要注意的是,如果要获取枚举里面的 Field、Method、Constructor 可以调用 Class 的通用 API。