从隐藏它的 class 的 subclass 访问隐藏字段
Access hidden field from subclass of class that hides it
如何访问被基 class 中的字段隐藏的基 class 的基 class 中的 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
class的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
}
}
有没有办法做到这一点而不需要反思,并且不改变超级classes?
不起作用?
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();
}
}
如果class在同一个包中,那么你可以将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;
}
}
请注意,这仅适用于 classes 在同一包中的情况。在您的示例中,classes 位于不同的包中,因此由于该字段是 protected
,您将遇到编译错误。
在这种情况下,由于 Java 语言规范的这一部分(§6.6.2,强调我的),无法不经反射地访问 A
的字段:
Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.
In addition, if Id denotes an instance field or instance method, then:
- ...
- If the access is by a field access expression E.Id, or a method invocation expression E.Id(...), or a method reference expression E :: Id, where E is a Primary expression (§15.8), then the access is permitted if and only if the type of E is S or a subclass of S.
这里你写的class是C
,所以superclassA
的protected字段只能通过像[=这样的表达式访问20=] 如果表达式的类型是 C
或 C
的子 class。但在那种情况下,.x
将始终解析为 B
的字段而不是 A
的字段。
从逻辑上讲,C
中的任何字段访问表达式都不允许访问 A
的字段。
我们也可以排除其他类型的可以访问字段的表达式:a simple name x
doesn't work, and a super expression cannot be chained like super.super.x
(see this answer).
如何访问被基 class 中的字段隐藏的基 class 的基 class 中的 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
class的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
}
}
有没有办法做到这一点而不需要反思,并且不改变超级classes?
不起作用?
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();
}
}
如果class在同一个包中,那么你可以将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;
}
}
请注意,这仅适用于 classes 在同一包中的情况。在您的示例中,classes 位于不同的包中,因此由于该字段是 protected
,您将遇到编译错误。
在这种情况下,由于 Java 语言规范的这一部分(§6.6.2,强调我的),无法不经反射地访问 A
的字段:
Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.
In addition, if Id denotes an instance field or instance method, then:
- ...
- If the access is by a field access expression E.Id, or a method invocation expression E.Id(...), or a method reference expression E :: Id, where E is a Primary expression (§15.8), then the access is permitted if and only if the type of E is S or a subclass of S.
这里你写的class是C
,所以superclassA
的protected字段只能通过像[=这样的表达式访问20=] 如果表达式的类型是 C
或 C
的子 class。但在那种情况下,.x
将始终解析为 B
的字段而不是 A
的字段。
从逻辑上讲,C
中的任何字段访问表达式都不允许访问 A
的字段。
我们也可以排除其他类型的可以访问字段的表达式:a simple name x
doesn't work, and a super expression cannot be chained like super.super.x
(see this answer).