2013-10-18 21 views
2

我注意到一些奇怪的行为。我有以下类:在构造函数中加载的Java属性值在构造函数之后被还原?

public abstract class BaseFoo 
{ 
    public BaseFoo(String key) 
    { 
     Data data = Something.load(key); 
     load(data); 
    } 

    public abstract void load(Data data); 
} 


public class Foo extends BaseFoo 
{ 
    @Expose public long id = 0; 
    @Expose public String name = ""; 
    //... 

    public Foo(String key) 
    { 
     super(key); 
    } 

    @Override 
    public void load(Data data) 
    { 
    this.id = data.id; 
    this.name = data.name; 
    //snip setting misc other fields 
    } 
} 

现在,如果我做到以下几点:

Foo f = new Foo ("abcd"); 

那么我期待f.id包含其中装载的Foo记录的ID。但是,它的价值实际上是0。通过调试器运行此代码,我发现在执行public long id = 0行之前调用Foo.load()。所以,尽管load()被调用,它不设置id等领域他们正确的价值观,这些价值观然后由public long id = 0;和其他变量声明覆盖..

我从来没有碰到过这样的问题之前,通常值在构造函数中设置覆盖变量声明中的默认值。是因为我通过super调用了负载的值,这些值被覆盖了吗?如果是这样,这是否有一个方便的解决办法?

+0

'long'的默认值是'0L','String'是'null'。如果你做一个简单的检查来返回一个空字符串而不是'null',你可以通过删除初始值来绕过这个问题。 –

+0

@JeroenVannevel这个班只是一个片段,我总共有10-12个字段。我不想做'if'检查10-12次,以避免获得nullpointerexceptions。 –

+0

可能重复[在构造函数中可重复方法调用有什么问题?](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors) – Joe

回答

7

这是调用构造函数的虚方法的问题...

执行的顺序是:

  • BaseFoo变量初始化
  • BaseFoo构造体
  • 富变量初始化
  • Foo构造函数体

该行为在JLS, section 12.5中有详细记录。

所以实际上,如果你改变这些:

@Expose public long id = 0; 
@Expose public long name = ""; 

@Expose public long id; 
@Expose public String name; 

然后有条件设置name为 “” 如果它不是已经被时间非空你进入Foo构造函数体,那么我认为你会没事的。

但是,我会强烈建议您以不同的设计来解决这个问题。构造函数中的虚方法调用很快就会变得非常混乱。

+0

只是想建议http ://www.yoda.arachsys.com/csharp/constructors.html :) – Vlad

+0

如果我将'BaseFoo(String key)'重命名为'BaseFoo',该怎么办?load(String key)',并从'Foo'的构造函数中执行:'load(key)',是否会导致值设置正确? –

+1

@ClickUpvote:是的,那是一种选择。 –

相关问题