一个受保护的变量是可访问的,而另一个则不可访问。为什么?

One protected variable is accessible while the other isn't. Why?

这是一道受保护的继承题。我确实理解 protected 意味着在一个包中,就好像它是 public。在包外,一般来说,只有在 subclass 内部时才能访问它。那不是我的困惑。我的困惑在于正在发生的一个小问题,我不知道为什么。我将在代码之后解释问题的内容。您将获得包含 TestA class 的包 com.wobble.foo 和包含扩展 classA.

的 TestB class 的 com.wobble.bar
//A Package
package com.wobble.foo;

public class TestA{
    static protected int x = 5;
    protected int y = 6;
}

//A different Package
package com.wobble.bar;

public class TestB extends TestA{
    static{
        TestA t = new TestA();
        t.x = 1; //compiles
        t.y = 2; //field not visible, fails to compile
    }
}

super class 有两个受保护的变量,一个是静态的。不同包中的 subclass 创建了一个新的 superclass 对象,试图访问这两个变量。为什么您可以通过对象访问静态变量,但不能通过它访问实例变量?他们都受到保护。两者来自同一个 class。两者都由同一个对象访问。请注意,对于那些认为这可能是重复的人:其他问题只是询问 protected 如何工作,但他们没有提出具体问题,即为什么只能访问这两个受保护的变量之一。

这不是一个如何修复代码的问题。我知道如何让游戏结束。问题是为什么可以通过 t.x; 而不是 t.y;?

 t.x = 1; //compiles

这是一个 static 字段。所以你应该把它写成 TestA.x (会有一个编译器警告)。

静态保护字段可从子classes 的静态代码中访问(或从非静态代码中访问)。

 t.y = 2; //field not visible, fails to compile

这是一个实例字段。受保护的实例字段可以从 subclasses 上的实例方法中访问。但只能从这些方法中进行。您不能从静态方法调用它们(即使该静态方法恰好位于子class)。

如果您需要从另一个 class 中的静态方法访问这些字段,您需要创建该字段 public 或将需要它的代码移动到同一个包中。


But only from within those methods.

并且只有在您可以确定所讨论的实例实际上来自您自己的情况下 class。

在你的例子中

TestA t = new TestA();
t.y = 2;

t.y 不可见,因为 TestB 中的代码无法访问 TestA 中实例的受保护字段。 。不过,相同的代码可以在 TestA 上的方法内部运行。

以下也不起作用:

// in TestB
void boo(TestA someInstance){
   this.y = someInstance.y; 
   // does not compile, because someInstance.y is not visible
   // because it could be from unknown TestC
}

Ok that makes sense but then how can I access t.x? It is a protected member too and I am still not t.

这里根本没有使用实例 t(它 could even be null and the code would still work). A static method is only dispatched on the compile-time (declared) type of the variable. Ideally, t.x should not even be allowed,但至少你会得到一个编译器警告。


it is static so technically you aren't accessing it via the superclass, but through the subclass? i.e. t.x -> x -> TestB.x which gets it via TestB?

静态方法不能被子class重写。 TestB.x 只是一种令人困惑的(或方便的,取决于您如何看待它)写 TestA.x 的方式。您可以将其视为子 class 从父 class 自动导入所有(public 和受保护的)静态字段和变量。减少击键次数,但不会改变行为(当然与实例方法有很大不同,实例方法是在实际实例类型上动态调度的)。

无论哪种方式,因为 TestA.x 是受保护的,它可以被 TestA 的子 class 中的静态代码块访问,包括 TestB.