为什么在传播之前必须复制反射成员?

时间:2018-09-30 08:50:26

标签: java reflection copy jdk-internal-api

如果查看获取字段,方法或构造函数的反射对象的源代码,则会返回其副本。让我们以获取字段为例:

    /**
 * Returns an array of {@code Field} objects reflecting all the fields
 * declared by the class or interface represented by this
 * {@code Class} object. This includes public, protected, default
 * (package) access, and private fields, but excludes inherited fields.
 *
 * <p> If this {@code Class} object represents a class or interface with no
 * declared fields, then this method returns an array of length 0.
 *
 * <p> If this {@code Class} object represents an array type, a primitive
 * type, or void, then this method returns an array of length 0.
 *
 * <p> The elements in the returned array are not sorted and are not in any
 * particular order.
 *
 * @return  the array of {@code Field} objects representing all the
 *          declared fields of this class
 * @throws  SecurityException
 *          If a security manager, <i>s</i>, is present and any of the
 *          following conditions is met:
 *
 *          <ul>
 *
 *          <li> the caller's class loader is not the same as the
 *          class loader of this class and invocation of
 *          {@link SecurityManager#checkPermission
 *          s.checkPermission} method with
 *          {@code RuntimePermission("accessDeclaredMembers")}
 *          denies access to the declared fields within this class
 *
 *          <li> the caller's class loader is not the same as or an
 *          ancestor of the class loader for the current class and
 *          invocation of {@link SecurityManager#checkPackageAccess
 *          s.checkPackageAccess()} denies access to the package
 *          of this class
 *
 *          </ul>
 *
 * @since 1.1
 * @jls 8.2 Class Members
 * @jls 8.3 Field Declarations
 */
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
    }
    return copyFields(privateGetDeclaredFields(false));
}

// Returns an array of "root" fields. These Field objects must NOT
// be propagated to the outside world, but must instead be copied
// via ReflectionFactory.copyField.
    private Field[] privateGetDeclaredFields(boolean publicOnly) {
    Field[] res;
    ReflectionData<T> rd = reflectionData();
    if (rd != null) {
        res = publicOnly ? rd.declaredPublicFields : rd.declaredFields;
        if (res != null) return res;
    }
    // No cached value available; request value from VM
    res = Reflection.filterFields(this, getDeclaredFields0(publicOnly));
    if (rd != null) {
        if (publicOnly) {
            rd.declaredPublicFields = res;
        } else {
            rd.declaredFields = res;
        }
    }
    return res;
}

    private static Field[] copyFields(Field[] arg) {
    Field[] out = new Field[arg.length];
    ReflectionFactory fact = getReflectionFactory();
    for (int i = 0; i < arg.length; i++) {
        out[i] = fact.copyField(arg[i]);
    }
    return out;
}

在jdk.internal.reflect.ReflectionFactory中

    /** Makes a copy of the passed field. The returned field is a
    "child" of the passed one; see the comments in Field.java for
    details. */
public Field copyField(Field arg) {
    return langReflectAccess().copyField(arg);
}

在java.lang.reflect.Field中

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

并且在java.lang.reflect.ReflectAccess(jdk的实现

    public Field       copyField(Field arg) {
    return arg.copy();
}

最后回到java.lang.reflect.Field

    /**
 * Package-private routine (exposed to java.lang.Class via
 * ReflectAccess) which returns a copy of this Field. The copy's
 * "root" field points to this Field.
 */
Field copy() {
    // This routine enables sharing of FieldAccessor objects
    // among Field objects which refer to the same underlying
    // method in the VM. (All of this contortion is only necessary
    // because of the "accessibility" bit in AccessibleObject,
    // which implicitly requires that new java.lang.reflect
    // objects be fabricated for each reflective call on Class
    // objects.)
    if (this.root != null)
        throw new IllegalArgumentException("Can not copy a non-root Field");

    Field res = new Field(clazz, name, type, modifiers, slot, signature, annotations);
    res.root = this;
    // Might as well eagerly propagate this if already present
    res.fieldAccessor = fieldAccessor;
    res.overrideFieldAccessor = overrideFieldAccessor;

    return res;
}

但是为什么呢?我们不能简单地访问根Field对象并弄乱它吗?

1 个答案:

答案 0 :(得分:2)

我不是具有反思能力的专家,所以可能还有其他原因。但是字段是可变的(setAccessible())。不返回副本意味着在代码的一部分中使其可访问,即使在依赖于该字段不可访问或不允许其可访问的其他代码中,也可以在任何地方访问它。