How can you access a protected field in a base class's base class that is hidden by a field in a base class?
An example:
package foo;
public class Foo {
protected int x;
int getFooX() { return x; }
}
package bar;
public class Bar extends foo.Foo {
protected int x;
// Can access foo.Foo#x through super.x
}
The Foo class's x field is shadowed by Bar's field of the same name, but can be accessed by reflection:
package baz;
public class Baz extends bar.Bar {
{
// Want getFooX() to return 2
// ((foo.Foo) this).x = 2; // Fails due to access error; Makes sense
// super.x = 2; // Changes bar.Bar#x
// super.super.x = 2; // Syntax error
// foo.Foo.this.x = 2; // Syntax error
try {
Field Foo_x = foo.Foo.class.getDeclaredField("x");
Foo_x.setAccessible(true);
Foo_x.setInt(this, 2);
} catch (ReflectiveOperationException e) { e.printStackTrace(); }
// Doesn't compile error if field changes name
}
}
Is there a way to do this without reflection, and without making changes to the superclasses?
If the classes are in the same package, then you can cast
thisto the type you want to access the field of. Field names are resolved statically, based on the compile-time type of the expression on the left of the., so the code below accessesA's field because the expression((A) this)has compile-time typeA.Note that this works only in the case where the classes are in the same package. In your example the classes are in different packages, so because the field is
protectedyou'll get a compilation error.In this case, it is impossible to access
A's field without reflection, because of this part of the Java Language Specification (§6.6.2, emphasis mine):Here the class you're writing in is
C, so the protected field of the superclassAis only accessible by an expression like(expr).xif the expression's type isCor a subclass ofC. But in that case, the.xwill always resolve toB's field rather thanA's field.Logically, it follows that accessing
A's field is not permitted by any field access expression inC.We can also rule out the other kinds of expressions which can access a field: a simple name
xdoesn't work, and a super expression cannot be chained likesuper.super.x(see this answer).