【问题标题】:One protected variable is accessible while the other isn't. Why?一个受保护的变量是可访问的,而另一个则不是。为什么?
【发布时间】:2019-08-07 17:05:10
【问题描述】:

这是一个受保护的继承问题。我确实理解 protected 意味着在一个包中,它就好像它是公共的。在包之外,一般来说,只有在子类内部时才能访问它。那不是我的困惑。我的困惑在于正在发生的一个小问题,我不知道为什么。我将在代码之后解释问题的核心。您将获得包含 TestA 类的包 com.wobble.foo 和包含扩展类 A 的 TestB 类的 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
    }
}

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

这不是一个如何修复代码的问题。我知道如何让最终游戏发挥作用。问题是为什么它可以通过t.x; 而不是t.y; 访问?

【问题讨论】:

  • 您永远不会在代码中实例化 TestB 对象,代码的最后三行位于静态初始化块中,不需要实例即可运行。
  • 另外:t.x 应该是T.x(因为它是一个静态方法调用);如果您的代码只是在TestB 对象的非静态方法中运行,您将能够访问y;您甚至不需要说出对象名称 y 而不是 t.y
  • @MikaelF 无论我将代码放在静态初始化程序还是实例初始化程序中,都不会改变结果。重点是通过 TestA 对象访问它。
  • T.y 不可访问,因为作为受保护的字段,它只能被其后代访问(在本例中为 t)。但是,您不是从t 访问它,而是从类TestA 内的一个静态块访问它。受保护类似于私有,但类可以访问它们从父类继承的字段和方法。
  • @user11214549 您可以通过两种方式看到这一点:1) 您正在尝试访问 t 的受保护成员,但它不会让您访问,因为您不是 t (请参阅我关于受保护类似于私有的评论); 2)您正在从静态上下文访问非静态字段,这是您无法做到的。您的最后 3 行没有在 t 内运行;相反,它们是静态运行的,不属于任何特定实例。不在t 内部运行的代码看不到t 不会在其自身及其依赖项之外显示的字段。此外,t.x 具有误导性,因为它实际上只是 xx 是静态的)。

标签: java inheritance protected


【解决方案1】:
 t.x = 1; //compiles

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

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

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

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

如果您需要从另一个类中的静态方法访问字段,您需要将字段设为公共或将需要它的代码移到同一个包中。


但仅限于这些方法中。

只有当您可以确定相关实例实际上来自您自己的类时。

在你的例子中

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

t.y 不可见,因为TestB 中的代码无法访问来自TestA 的实例上的受保护字段。 It needs to be an instance of TestB。不过,相同的代码可以在 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
}

好吧,这是有道理的,但是我怎样才能访问 t.x?它也是受保护的成员,我仍然不是。

这里根本没有使用实例t(它could even be null 并且代码仍然可以工作)。静态方法仅在变量的编译时(声明的)类型上调度。理想情况下,t.xshould not even be allowed,但至少你会收到编译器警告。


它是静态的,所以从技术上讲,您不是通过超类访问它,而是通过子类访问它?即 t.x -> x -> TestB.x 通过 TestB 获得它?

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

不管怎样,因为TestA.x是受保护的,它可以被TestA的子类中的静态代码块访问,包括TestB

【讨论】:

    猜你喜欢
    • 2014-06-24
    • 2013-11-25
    • 2011-04-22
    • 2012-05-09
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    相关资源
    最近更新 更多