0

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

    /**
 * 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 对象并弄乱它吗?

4

1 回答 1

2

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

于 2018-09-30T08:59:56.353 回答