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

标签 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 对象并对其进行修改吗?

最佳答案

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

关于java - 为什么反射成员必须在传播之前复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52576306/

相关文章:

java - SetText 方法找不到 JTextField 的变量名称

java - 为什么 Java Reflection 找不到另一个包中类的包私有(private)构造函数?

java - "getDeclaredXyz"在Java反射包中代表什么

c++ - 复制构造函数

java - Cassandra Sync 和 Async,哪一个返回结果集更快?

java - UnsupportedClassVersionError : JVMCFRE003 bad major version in WebSphere AS 7

c# - Delegate 不包含 .net core 中 CreateDelegate 的定义

arrays - 将数组中的所有项复制到引用类型的新数组中的函数

javascript - 如何使用 br 断行制作(复制到剪贴板)

java - 单击显示 Iframe