在Java中,为什么我不能在父类中声明最终成员(没有初始化它)并在子类中设置它的值? 我该如何解决?

在Java程序中,我有多个从父类inheritance的子类(它是抽象的)。 我想表达的是,每个孩子都应该有一个只设置一次的成员(我打算从构造函数中做到这一点)。 我的计划是编码s.th. 喜欢这个:

public abstract class Parent { protected final String birthmark; } public class Child extends Parent { public Child(String s) { this.birthmark = s; } } 

然而,这似乎不能取悦Java神。 在父类中,我得到birthmark “可能尚未初始化”的消息,在子类中我得到“无法访问最终字段birthmark ”。

那么Java的方式是什么呢? 我错过了什么?

你不能这样做,因为在比较父类时,编译器不能确定子类是否会初始化它。 你必须在父的构造函数中初始化它,并让子调用父的构造函数:

 public abstract class Parent { protected final String birthmark; protected Parent(String s) { birthmark = s; } } public class Child extends Parent { public Child(String s) { super(s); ... } } 

将它传递给父构造函数:

 public abstract class Parent { private final String birthmark; public Parent(String s) { birthmark = s; } } public class Child extends Parent { public Child(String s) { super(s); } } 

另一种Java-ish方法可能是让父类定义一个抽象的“getter”,让孩子们实现它。 在这种情况下,这不是一个很好的方法,但在某些情况下,它可能正是你想要的。

我会这样做:

 public abstract class Parent { protected final String birthmark; protected Parent(final String mark) { // only if this makes sense. if(mark == null) { throw new IllegalArgumentException("mark cannot be null"); } birthmark = mark; } } public class Child extends Parent { public Child(final String s) { super(s); } } 

final意味着每个实例可以初始化一次变量。 编译器无法确保每个子类都提供胎记的赋值,因此它强制赋值在父类的构造函数中发生。

我添加了对null的检查只是为了表明你还能够在一个地方而不是每个cosntructor中检查参数。

为什么不将初始化委托给方法。 然后覆盖父类中的方法。

 public class Parent { public final Object x = getValueOfX(); public Object getValueOfX() { return y; } } public class Child { @Override public Object getValueOfX() { // whatever ... } } 

这应该允许自定义初始化。

是的,最终成员将被分配到声明它们的类中。 您需要向Parent添加带String参数的构造函数。

声明由子类调用的超类中的构造函数。 您必须在超类中设置字段以确保它已初始化,否则编译器无法确定该字段是否已初始化。

您可能希望拥有一个Parent(String birthmark)构造函数,以便您可以在Parent类中确保始终初始化final。 然后你可以从你的Child()构造函数调用super(胎记)。