如何访问基类中被字段隐藏的基类中的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
}
}
有没有办法做到这一点而无需反思,也无需更改超类?
答案 0 :(得分:1)
不行吗?
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();
}
}
答案 1 :(得分:1)
如果这些类位于同一包中,则可以将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语言规范(§6.6.2,这是我的重点)的这一部分,因此无法无反射地访问A
的字段:
让C为声明受保护成员的类。只能在C的子类S的主体内进行访问。
此外,如果Id表示实例字段或实例方法,则:
- ...
- 如果访问是通过字段访问表达式E.Id或方法调用表达式E.Id(...)或方法引用表达式E :: Id,其中E是主表达式(第15.8节) ,则仅当E类型为S或S的子类时,才允许访问。
这里您要写入的类是C
,因此,如果表达式的类型为{{1,则只能通过A
之类的表达式访问超类(expr).x
的受保护字段}}或C
的子类。但是在那种情况下,C
将始终解析为.x
的字段,而不是B
的字段。
从逻辑上讲,A
中的任何字段访问表达式都不允许访问A
的字段。
我们还可以排除可以访问字段的其他类型的表达式:simple name C
不起作用,super expression不能像{{1} }(请参阅this answer)。