从隐藏它的类的子类访问隐藏字段

问题描述 投票:1回答:2

如何访问基类中被字段隐藏的基类中的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
    }
}

是否有一种方法可以不进行反思,也无需更改超类?

java member-hiding
2个回答
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();
        }
    }

0
投票

如果类在同一包中,则可以将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)。] >

© www.soinside.com 2019 - 2024. All rights reserved.