使用final方法初始化实例变量

来自Sun的文档

通常,您可以使用代码在构造函数中初始化实例变量。
使用构造函数初始化实例变量有两种方法:初始化块和最终方法。

我可以理解初始化块的使用。 任何人都可以解释使用最终方法进行var初始化吗? 非最终的公共制定者可以完成这项工作。 为什么不直接使用它们?

优点已在您链接到的相同Sun教程中进行了描述:

无法在子类中重写最终方法。 这在接口和inheritance的课程中讨论。

如果子类可能想要重用初始化方法,这尤其有用。 该方法是最终的,因为在实例初始化期间调用非final方法可能会导致问题。 Joshua Bloch在Effective Java(第17项设计和inheritance文档)中更详细地描述了这一点。

非final方法在初始化中很危险的原因是因为超类的实例初始化在初始化子类之前执行。 因此,如果非最终方法在子类中被覆盖并且在超类的初始化期间执行,则它可能正在访问子类的未初始化字段,从而给出错误的结果。

一般规则是(引用Effective Java): 构造函数不能直接或间接调用可覆盖的方法。

它在参考教程的同一页面上进行了解释。 原因是up-subclass可以覆盖非final方法。 这是一个例子:

class Whatever { private List myVar = initializeInstanceVariable(); protected List initializeInstanceVariable() { return new ArrayList(); } } class Whoever extends Whatever { @Override protected List initializeInstanceVariable() { return Collections.unmodifiableList(super.initializeInstanceVariable()); } } 

因此,如果你创造了谁,myVar将变得不可修改;-)

其他例子

来自alykhantejani.github.io

我把它编译并简化了。

Duck.java

 public class Duck { String sound = "quack"; protected String speech; public Duck() { initSpeech(); } protected void initSpeech() { speech = "sound = " + sound; } public void speak() { System.out.println(speech); } protected String getSound() { return sound; } } 

SqueakyDuck

 public class SqueakyDuck extends Duck { String squeakSound = "squeak"; public SqueakyDuck() { super(); } @Override protected void initSpeech() { speech = "sound = " + squeakSound; } @Override protected String getSound() { return squeakSound; } } 

Main.java

 public class Main { public static void main(String[] args){ Duck squeaky = new SqueakyDuck(); squeaky.speak(); System.out.println(squeaky.getSound()); } } 

输出:

 sound = null squeak 

我的例子

Superclass.java

 public class Superclass { protected int x = m(); protected int m() { return 8; } } 

Subclass.java

 public class Subclass extends Superclass { private int y = 7; @Override protected int m() { return y; } } 

Main.java

 public class Main { public static void main(String[] args) { Superclass s = new Subclass(); System.out.println(sx); } } 

输出:

 0 

执行顺序:

  • main
  • m来自Subclass (此时y 未初始化0int的默认值)
  • 构造函数Superclass
  • 构造函数Subclass