2014-03-26 192 views
3

我正在收集个人备忘单的设计模板,并且我发现了一个至少对我而言奇怪的代码Head First Design Patterns(Eric Freeman,Elisabeth Robson,Bert Bates,Kathy Sierra)属性初始化Java

我不认为我确切地允许在这里发表的一段代码在写这本书,但我将重现让我震惊的代码:

假设我们先前deffined类A用公共方法runSomeCode(),然后我们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

我想我知道用的例子发生了什么事。

在书中,被引用的类是不是声明为静态,但几分钟前,我认为它可以编译,如果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

+0

它确实会抛出一个NPE,你可以(实际上)尝试它。 – m0skit0

+1

@ m0skit0你是对的我在深夜测试了这个案例,我可能做了一些不同的事情。然而,这本书的例子就是这样,所以书本错了,或者我是盲人/白痴 –

+1

书中的例子是错误的,有时会发生;) – m0skit0

回答

1

回答您的问题:

  1. 我相信你是错的,根据构造函数体前Java 8 Specification字段初始执行
  2. 我相信它有,但不想每个版本都通过规范。我不知道有任何变化。
  3. 我对此表示怀疑,看看它是如何成为规范的一部分,并且如果他们改变了它,会破坏兼容性。但是
  4. 在这种情况下,通过将赋值移动到构造函数x中,可以轻松地将代码更改为明确指出初始化的顺序。将它作为字段初始值设定器没有任何好处,这对我来说是显而易见的。

什么应该是这个“模式”的重点?你只需要两个引用,其中一个会完成......为什么不使用a呢?

1

我错了吗?

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

Java总是表现得像这样吗?

是的。

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

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

你会尽量避免它吗?

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

+0

我已经在这个问题中说过,据我所知,这是没有意义的。另一方面,我在深夜对它进行了测试,我想我可能做了一些不同的事情,但我会尽力重现它。 –

1

当您首次创建类型B的对象时,首先初始化具有任何初始化的字段。因此,即使在构造函数中的代码被执行之前,A x = a;被执行,它将x的值设置为null,因为a没有被实例化并且仅仅是类型A的空引用。之后,执行下面的代码创建两个对象。

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

此时x仍为空。所以当你尝试在使用x的A类中执行一个方法时,它会抛出一个空指针异常。

+0

我已经在这个问题中说过,据我所知,这是没有意义的。另一方面,我在深夜对它进行了测试,我想我可能做了一些不同的事情,但我会尽力重现它。 –