2

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

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

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

4

1 回答 1

7

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

执行顺序为:

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

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

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

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

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

然后有条件地设置name为 "" 如果在您到达构造函数主体时它还不是非空的Foo,那么我认为您会没事的。

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

于 2013-10-18T21:39:47.587 回答