如何访问基类中被字段隐藏的基类中的protected
字段?
示例:
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
}
Foo
类的x
字段被同名的Bar
的字段遮盖,但可以通过反射进行访问:
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
}
}
是否有一种方法可以不进行反思,也无需更改超类?
不工作吗?
public static void main(String... args) {
Baz b = new Baz();
try {
Field Foo_x = Foo.class.getDeclaredField("x");
Foo_x.setAccessible(true);
Foo_x.setInt(b, 2);
System.out.println(b. getFooX());
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}
如果类在同一包中,则可以将this
强制转换为要访问其字段的类型。字段名称是根据.
左侧表达式的编译时类型静态解析的,因此下面的代码访问A
的字段,因为表达式((A) this)
具有编译时类型A
。
class A {
protected int x = 1;
}
class B extends A {
protected int x = 2;
}
class C extends B {
int getAx() {
return ((A) this).x;
}
void setAx(int x) {
((A) this).x = x;
}
}
注意,这仅在类位于同一包中的情况下有效。在您的示例中,这些类位于不同的程序包中,因此,因为该字段为protected
,您会收到编译错误。
在这种情况下,由于Java语言规范的这一部分(A
,我的重点是:),因此无法无反射地访问§6.6.2的字段:
让C为声明受保护成员的类。仅在C的子类S的主体内允许访问。
此外,如果Id表示实例字段或实例方法,则:
- ...
- [如果访问是通过字段访问表达式E.Id或方法调用表达式E.Id(...)或方法引用表达式E :: Id,其中E是主表达式(§15.8),然后[且仅当E的类型为S或S的子类时,才允许访问。
这里您要写入的类是C
,因此,如果表达式的类型是A
或(expr).x
的子类,则只有C
这样的表达式才能访问超类C
的受保护字段。但是在那种情况下,.x
将始终解析为B
的字段,而不是A
的字段。
逻辑上,A
中的任何字段访问表达式均不允许访问C
的字段。
[我们还可以排除可以访问字段的其他类型的表达式:simple name x
不起作用,并且super expression不能像super.super.x
那样链接(请参见this answer)。] >