从隐藏它的 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
}

Fooclass的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=] 如果表达式的类型是 CC 的子 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).