实例变量初始化中的问题 [英] Problem in instance variable initialization

查看:123
本文介绍了实例变量初始化中的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一些示例代码,

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

  }
}




输出:d.value()返回0 //我期望10,因为lookup()被覆盖,但不是0!有人可以澄清这个吗?

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

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

The initialization of Derived's instance variables has not happened at the time its lookup method executes. How do I make sure the instance variables of Derived are initialized when its method is called?

推荐答案

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

Well for a start, that code doesn't compile due to the lack of someLookup method.

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

Anyway, asides from that I believe your issue is that your expections are invalid because of the way constructors are run hierarchically.

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

A superclass' constructor is always run before the subclass', and this includes initializers for the subclass' variables (which are really run as part of the constructor). So, when you create your instance of Derived, the following happens:


  1. 首先调用Base 构造函数。

  2. lookup()被调用,其中使用派生中的实现。

  3. num 返回这是默认值,因为Derived的构造函数和初始值设定项尚未运行

  4. val 设置为0。

  5. 运行派生的初始值设定项和构造函数 - 从 lookup 调用点将返回10.

  1. The Base constructor is invoked first.
  2. lookup() is called, which uses the implementation in Derived.
  3. num is returned, which is the default value at this point because Derived's constructor and initializers have not been run.
  4. val is set to 0.
  5. The Derived initializers and constructor are run - calling lookup from this point on will return 10.

一般情况下,召唤非决赛是一个坏主意正是出于这个原因,来自构造函数的方法,许多静态分析工具会警告你不要这样做。它类似于在构造过程中让对象引用泄漏,你最终会得到一个使类级别不变量无效的实例(在你的情况下,Derived的 num 是总是10但它可以看出在某些时候为0)。

In general, it's a bad idea to call a non-final method from a constructor for exactly this reason, and many static analysis tools will warn you against it. It's similar to letting object references leak during construction, you can end up with an instance that invalidates class-level invariants (in your case, Derived's num is "always" 10 yet it can be seen to be 0 at some points).

编辑:请注意,对于此特定的情况,没有任何其他代码,您可以解决使 num 一个常数的问题:

Note that for this particular case, without any additional code, you could resolve the issue by making num a constant:

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

这实际上会做你想要的,因为运行静态初始化程序加载类时(必须在调用构造函数之前发生)。但是,这确实适用于:

This would actually do what you want, because the static initializer is run when the class is loaded (which has to happen before the constructors are called). This does however assume that it's fine for:

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

a) all instances of the class to share the same num variable; b) num never needs to change (if this is true then (a) is true automatically).

在您给出的确切代码中显然是这种情况,但我希望您可能省略额外的功能以简洁。

In the exact code you've given this is clearly the case, but I expect you may be omitting extra functionality for brevity.

我在此处包含此信息用于比较和兴趣,不是因为它是一般意义上的这个问题的解决方法(因为它不是)。

I include this here for comparison and interest, not because it's a workaround to this "issue" in a general sense (because it's not).

这篇关于实例变量初始化中的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆