简体   繁体   English

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

[英]Access hidden field from subclass of class that hides it

How can you access a protected field in a base class's base class that is hidden by a field in a base class? 如何访问基类的字段隐藏的基类的基类中的protected字段?

An example: 一个例子:

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
}

The Foo class's x field is shadowed by Bar 's field of the same name, but can be accessed by reflection: 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
    }
}

Is there a way to do this without reflection, and without making changes to the superclasses? 有没有办法做到这一点而无需反思,也无需更改超类?

Doesn't work? 不行吗

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();
        }
    }

If the classes are in the same package, then you can cast this to the type you want to access the field of. 如果类在同一个包,那么你可以施放this向您要访问的字段类型。 Field names are resolved statically, based on the compile-time type of the expression on the left of the . 字段名称是根据左侧表达式的编译时类型静态解析的. , so the code below accesses A 's field because the expression ((A) this) has compile-time type A . ,因此下面的代码访问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;
    }
}

Note that this works only in the case where the classes are in the same package. 请注意,这仅在类位于同一包中的情况下有效。 In your example the classes are in different packages, so because the field is protected you'll get a compilation error. 在您的示例中,这些类位于不同的程序包中,因此,由于该字段protected ,因此会出现编译错误。

In this case, it is impossible to access A 's field without reflection, because of this part of the Java Language Specification ( §6.6.2 , emphasis mine): 在这种情况下,由于Java语言规范的这一部分(第6.6.2节 ,重点是我的内容),因此无法无反射地访问A的字段:

Let C be the class in which a protected member is declared. 令C为声明受保护成员的类。 Access is permitted only within the body of a subclass S of C. 仅在C的子类S的主体内允许访问。

In addition, if Id denotes an instance field or instance method, then: 另外,如果Id表示实例字段或实例方法,则:

  • ... ...
  • 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 . 如果接入是由现场访问表达式E.Id或方法调用表达式E.Id(...)的方法,或者参考表达式E :: ID,其中E是一个主表达式(§15.8), 则当且仅当E的类型为S或S的子类时,才允许访问

Here the class you're writing in is C , so the protected field of the superclass A is only accessible by an expression like (expr).x if the expression's type is C or a subclass of C . 这是在写类,你是C ,所以超类的保护领域A是唯一可通过类似表达式(expr).x如果表达式的类型是C或子类C But in that case, the .x will always resolve to B 's field rather than A 's field. 但是在那种情况下, .x将始终解析为B的字段而不是A的字段。

Logically, it follows that accessing A 's field is not permitted by any field access expression in C . 从逻辑上讲, C任何字段访问表达式都不允许访问A的字段。

We can also rule out the other kinds of expressions which can access a field: a simple name x doesn't work, and a super expression cannot be chained like super.super.x (see this answer ). 我们还可以排除可以访问字段的其他类型的表达式: 简单名称 x无效,并且超级表达式不能像super.super.x一样super.super.x (请参见此答案 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM