在构造函数中加载的Java属性值是在构造函数之后还原的?

时间:2013-10-18 21:34:23

标签: java oop

我注意到一些奇怪的行为。我有以下课程:

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。通过调试器运行此代码,我发现在Foo.load()行执行之前调用了public long id = 0。因此,虽然load()被调用并且它确实将id和其他字段设置为正确的值,但这些值会被public long id = 0;和其他变量声明覆盖..

我之前从未遇到过这个问题,通常在构造函数中设置的值会覆盖变量声明中的默认值。是因为我通过super调用加载值是否被覆盖?如果是这样,是否有方便的解决方法呢?

1 个答案:

答案 0 :(得分:7)

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

执行顺序是:

  • BaseFoo变量初始值设定项
  • BaseFoo构造函数体
  • Foo变量初始值设定项
  • Foo构造函数主体

JLS, section 12.5中记录了这种行为。

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

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

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

然后有条件地name设置为“”,如果它到达Foo构造函数体时尚未为空,那么我认为你会没关系。

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