简体   繁体   English

构造函数中加载的Java属性值将在构造函数之后恢复吗?

[英]Java property values loaded in constructor are being reverted after the constructor?

I'm noticing some strange behavior. 我注意到一些奇怪的行为。 I have the following classes: 我有以下课程:

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
   }
}

Now, if I do the following: 现在,如果我执行以下操作:

Foo f = new Foo ( "abcd" );

Then I expect f.id to contain the id of the Foo record which was loaded. 然后我希望f.id包含加载的Foo记录的id。 However, its value is actually 0 . 但是,它的值实际上是0 By running this code through a debugger, I've found that Foo.load() is called before the public long id = 0 line is executed. 通过调试器运行此代码,我发现在执行public long id = 0行之前调用了Foo.load() So, although load() is called and it does set id and other fields to their correct values, those values are then overwritten by the public long id = 0; 因此,尽管调用了load()并且确实将id和其他字段设置为其正确的值,但是这些值随后被public long id = 0;覆盖public long id = 0; and other variable declarations.. 和其他变量声明..

I've never come across this issue before, usually the values set in a constructor overwrite the default values in the variable declaration. 我以前从未遇到过此问题,通常在构造函数中设置的值会覆盖变量声明中的默认值。 Is it because I'm calling load through super that the values are being overwritten? 是因为我通过super调用负载值是否被覆盖? If so, is there a convenient fix for this? 如果是这样,是否有一个方便的解决方法?

This is the problem with calling virtual methods in a constructor... 这是在构造函数中调用虚方法的问题...

The order of execution is: 执行顺序为:

  • BaseFoo variable initializers BaseFoo变量初始化器
  • BaseFoo constructor body BaseFoo构造函数主体
  • Foo variable initializers Foo变量初始值设定项
  • Foo constructor body Foo构造函数主体

That behaviour is well documented in the JLS, section 12.5 . 这种行为在JLS第12.5节中有详细记载。

So actually , if you change these: 实际上 ,如果你改变这些:

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

to

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

and then conditionally set name to "" if it's not already non-null by the time you get to the Foo constructor body, then I think you'll be okay. 然后有条件地name设置为“”,如果到Foo构造函数主体时name还不是非null的话,那么我认为您会没事的。

However, I'd strongly advise you to approach this with a different design. 但是,我强烈建议您采用其他设计方法。 Virtual method calls in constructors get really messy really quickly. 构造函数中的虚方法调用非常快速地变得非常混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM