【问题标题】:Shadowing / Scope of Variables阴影/变量范围
【发布时间】:2016-01-31 13:46:51
【问题描述】:

我以为我理解了阴影的概念。但是这段代码让我想知道:

public class Counter {
int count = 0;

public void inc() {
    count++;
}

public int getCount() {
    return count;
}

}

class StepCounter extends Counter {
int count = 0;
int step = 1;

public StepCounter(int step) {
    this.step = step;
}

public void inc() {
    count += step;
}

}

StepCounter sc = new StepCounter(2);
    sc.inc();
    sc.inc();
    System.out.println(sc.getCount());
    System.out.println(sc.count);

所以基本上 sc 的静态类型是StepCounter。 它的计数器增加了两次,所以它在前两个命令之后是 4。 我的 count 变量不是私有变量,它是包私有的(因为我没有声明任何可见性)。 因此,如果我在 sc 上调用.getCount() 方法,它首先会在 StepCounter 中查找它。没有,所以它转到柜台。在这里它找到了getCount() 方法。 该方法返回计数。如果 count 是静态的或私有的,我会理解为什么它返回 0。但是为什么在这种情况下它会返回 0?即使我在StepCounter 中公开了变量计数,结果仍然是0。

【问题讨论】:

  • 因为成员变量不是多态的。 Counter.getCount 总是返回 Counter.count。
  • 这里的字段也没有阴影。它被隐藏了。
  • 我仍然很难,在“相关”答案中很容易看到 b/c 方法是静态的。在我的情况下,它们不是。你是说成员变量(在类范围内创建的变量)总是静态的?

标签: java dynamic static shadowing


【解决方案1】:

getCount() 只能访问在父类中定义的字段counter。此类在父类的编译时解析。子进程中没有方法getCounter()副本

在子类中,可以使用

Counter.this.count

访问父计数器。但为避免意外,您永远不应该以如此含糊的方式命名一个字段。

【讨论】:

    【解决方案2】:

    您应始终尽可能避免阴影,它可能会为您的代码引入严重的不可预测的行为。 您在这里缺少的是 Java 中变量作用域的概念。 count 只是this.count 的简写。因此,鉴于您的代码,在调用 getCounter() 方法之后,解析器在此处所做的是:

    1. 尝试将getCounter() 解析为StepCounter 类的实例
    2. 失败,尝试查找任何类祖先
    3. 最近的祖先是Counter,所以上下文切换Counter
    4. 尝试在Counter类中解析getCounter()
    5. 方法找到,尝试解析count的值
    6. getCounter() 是非静态的,所以 count 实际上是 this.count(如果 getCounter() 是静态的,它将是 Counter.count
    7. this.countCounter 类的实例范围内解析为值 0
    8. 0 被退回

    【讨论】:

    • this 在构造函数作用域之外是指当前对象,对吧?所以 this.getClass() 是 StepCounter,所以我仍然无法弄清楚第 7 步..
    • getClass() 为您提供构建实例的类的参考。在您的示例中,您创建的 sc 实例中有两个单独的 count 属性值。一个在StepCounter 类的上下文中,一个在Counter 类的上下文中。您可以自己尝试,只需在代码末尾添加以下行:System.out.println(((Counter) sc).count);。在getCounter()方法范围内的this(Counter) this的值。
    • 非常感谢!所以每当我把这个写成一个反对引用时,它就等于写(我正在写这个的类的演员)这个。这是正确的吗?
    【解决方案3】:

    在 Java 中,字段不能被覆盖。只有方法可以被覆盖。因此,在 StepCounter 中有一个“count”变量不会覆盖超类“Counter”中的“count”字段。它只是创建了另一个字段。然而,“getCount”方法返回超类中“count”字段的值。要获得所需的功能,需要覆盖 StepCounter 类中的“getCount”方法。

    【讨论】:

    • 我的对象具有动态类型计数器。现在 getCount() 方法说“返回名为 count 的字段”。它不应该先查看自己的范围(B)吗?
    • @InDaPond 字段永远不能被覆盖,因此当执行 getCount 方法时,它会看到仅在超类中定义的 'count' 字段
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 2013-06-15
    相关资源
    最近更新 更多