java - 实例变量初始化的问题

标签 java instance instance-variables

这是一些示例代码,

class Base
{
  private int val;

  Base() {
  val = lookup();
  }

  public int lookup() {
    //Perform some lookup
  // int num = someLookup();
  return 5;
  }

  public int value() {
  return val;
  }
}

class Derived extends Base
{
  private int num = 10;

  public int lookup() {
  return num;
  }
}


class Test
{
  public static void main(String args[]) {

  Derived d = new Derived();
  System.out.println("d.value() returns " + d.value());

  }
}

output: d.value() returns 0 // I expected 10 as lookup() is overridden, but not 0! can someone clarify this?

Derived 的实例变量的初始化在其查找方法执行时尚未发生。如何确保 Derived 的实例变量在其方法被调用时被初始化?

最佳答案

首先,由于缺少 someLookup 方法,该代码无法编译。

无论如何,除此之外,我认为您的问题是由于构造函数的分层运行方式,您的期望是无效的。

父类(super class)的构造函数总是在子类之前运行,这包括子类变量的初始值设定项(它们实际上是作为构造函数的一部分运行的)。因此,当您创建 Derived 实例时,会发生以下情况:

  1. 首先调用Base 构造函数。
  2. lookup() 被调用,它使用了 Derived 中的实现。
  3. 返回
  4. num这是此时的默认值,因为Derived的构造函数和初始化器还没有运行
  5. val 设置为 0。
  6. Derived 初始化程序和构造函数已运行 - 从this 点调用lookup 将返回 10。

一般来说,正是出于这个原因,从构造函数中调用非 final 方法是个坏主意,许多静态分析工具都会警告您不要这样做。这类似于在构造期间让对象引用泄漏,您最终可能会得到一个使类级不变量无效的实例(在您的情况下,Derived 的 num “始终”为 10 但它可以被视为 0在某些时候)。

编辑:请注意,对于这种特殊情况,无需任何额外代码,您可以通过将 num 设为常量来解决问题:

class Derived extends Base
{
  private static final int num = 10;
  ...

这实际上会做你想做的,因为静态初始化器在加载类时运行(这必须在调用构造函数之前发生)。然而,这确实假设它适用于:

a) 该类的所有实例共享相同的 num 变量; b) num 永远不需要改变(如果这是真的那么 (a) 自动为真)。

在您给出的确切代码中,情况显然如此,但我希望您可能会为了简洁而省略额外的功能。

我将其包含在这里是为了比较和兴趣,而不是因为它是一般意义上这个“问题”的解决方法(因为它不是)。

关于java - 实例变量初始化的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3288601/

相关文章:

java - System.in.read() 不读取

python - 在python中获取类和实例的属性

Android 静态变量作用域和生命周期

ruby-on-rails - Rails 模型中的实例变量

python - 如何在Python中创建多个类实例?

dsl - Xtext如何通过实例通过限定名称引用变量?

java - 查找关联的 mybatis 查询

java - 在struts的forward标签中添加点是什么意思?

java - 在 Java 中生成 UUID 版本 2

ruby - 动态添加 ruby​​ 类方法或实例方法