If you look into the source code of getting reflective objects of fields, methods or constructors, their copies are returned. Lets take getting field as example:
/**
* 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));
}
And
// 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;
}
And
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;
}
And in 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);
}
And in 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;
And in java.lang.reflect.ReflectAccess (implementation of jdk
public Field copyField(Field arg) {
return arg.copy();
}
And finally back to 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;
}
But why? Cannot we just simply access the root Field object and mess with it?
Aucun commentaire:
Enregistrer un commentaire