属性初始化Java

时间:2014-03-26 10:41:50

标签: java constructor

我正在为个人备忘单收集设计图案,我在头部设计模式(由Eric Freeman,Elisabeth Robson,Bert Bates,Kathy Sierra)发现了至少对我来说奇怪的代码< / em>的

我不认为我可以在这里发布完整的代码片段,但是我会重现让我震惊的代码:

假设我们之前使用公共方法runSomeCode()定义了类A,那么我们将使用以下类B:

public class B {

    A a;
    A b;
    A x = a;

    public B() {
        a = new A();
        b = new A();
    }

    public void testB()
    {
        x.runSomeCode();
    }    
}

我对此代码的第一印象是,对B实例testB方法的任何调用都应抛出NullPointerException,但我无法想象他们会发布这样的错误。

如果这本书是对的,那么我理解

x = a;

必须在B构造函数执行结束时完成,但我仍然对这个sintaxis感到惊讶,我的问题是:

  • 我错了吗?
  • Java总是表现得像这样吗?
  • 在这种情况下(我个人认为这有点令人困惑):是否可能在将来的Java版本中删除它?
  • 你会试着避免吗?

编辑这是本书的例子:

enter image description here

我担心的情况是numberGumballs = 0;

编辑II

我想我知道这个例子发生了什么。

在本书中,引用的类是 NOT 声明为静态,但几分钟前,我认为如果A是静态的,它可以编译。所以,也许,这本书的作者从一个更大的项目中获得了代码,其中使用了静态类。所以我尝试了这一点,这次它确实有效,但是这个例子似乎仍然是错误的,以下代码对State pattern没有任何意义。

public class B {

    public static class Base {
        public static void runSomeCode() { System.out.println("Base!"); }
    }

    public static class A extends Base {
        public static void runSomeCode() { System.out.println("A!"); }
   }; 

    A a;
    A b;
    A x = a;

    public B() {
        a = new A();
        b = new A();
    }

    public void testB()
    {
        x.runSomeCode();
    }    
}

又一个编辑

在书中的例子中,我似乎并不是第一个注意到这个问题的人, 在O'Reilly site errata section, under unconfirmed erratas sub-section你可以找到:

enter image description here

3 个答案:

答案 0 :(得分:1)

  

我错了吗?

就地变量初始化在构造函数初始化之前工作,其顺序与代码中定义的变量相同。

  

Java总是表现得像这样吗?

  

在那种情况下(我个人认为这有点令人困惑):是   它可能会在未来的Java版本中删除吗?

不,Java是向后兼容的语言,这是基本的,不会改变。

  

你会试着避免吗?

如果您想要就地初始化,请确保它与其他变量的初始化无关。否则在构造函数中初始化它。不要进行复杂的就地初始化。

答案 1 :(得分:1)

回答你的问题:

  1. 我认为你错了,根据Java 8 Specification字段初始值设定项在构造函数体之前执行
  2. 我相信它已经有了,但是不想让每个版本都遵守规范。我不知道有任何变化。
  3. 我怀疑它,看看它是如何成为规范的一部分,并且如果它们改变它会破坏兼容性。但
  4. 在这种情况下,可以通过将赋值移动到x到构造函数中,轻松地将代码转换为显式地说明初始化的顺序。将它作为字段初始化程序没有任何好处,这对我来说是显而易见的。
  5. 这应该是什么&#34;模式&#34;?你最后会得到两个参考文献,其中一个人会做...为什么不只是使用a

答案 2 :(得分:1)

首次创建B类型的对象时,首先初始化具有任何初始化的字段。因此,首先执行A x = a;,甚至在执行构造函数中的代码之前执行,该代码将x的值设置为null,因为尚未实例化并且只是类型A的空引用。在此之后,以下执行代码创建两个对象。

public B() {
    a = new A();
    b = new A();
}

此时x仍为null。因此,当您尝试使用x在A类中执行方法时,它将抛出空指针异常。