在Java中初始化final字段

16

我有一个类,其中有许多 final 成员,可以使用两个构造函数之一进行实例化。这些构造函数共享一些代码,该代码存储在第三个构造函数中。

// SubTypeOne and SubTypeTwo both extend SuperType

public class MyClass {
    private final SomeType one;
    private final SuperType two;


    private MyClass(SomeType commonArg) {
        one = commonArg;
    }

    public MyClass(SomeType commonArg, int intIn) {
        this(commonArg);

        two = new SubTypeOne(intIn);
    }

    public MyClass(SomeType commonArg, String stringIn) {
        this(commonArg);

        two = new SubTypeTwo(stringIn);
    }
问题在于这段代码无法编译:变量“two”可能未初始化。 有人可能会从MyClass内部调用第一个构造函数,然后新对象将没有设置“two”字段。
那么在这种情况下共享构造函数之间的代码的首选方式是什么?通常我会使用辅助方法,但是共享代码必须能够设置final变量,而这只能从构造函数中完成。

3
目前你有两个完全一样的构造函数(参数和函数体都相同),很难理解你的问题。你能否修复它使其更具代表性? - Jon Skeet
2
在第一个构造函数中,two 没有被初始化。 - Ryan Amos
5
@Jon Skeet - 请再仔细看一遍,参数类型是不同的。 - Don Roby
2
@DonRoby:谢谢,是的,我错过了那个。唉。 - Jon Skeet
4个回答

19
这个怎么样?(根据修改后的问题更新)
public class MyClass {

    private final SomeType one;
    private final SuperType two;

    public MyClass (SomeType commonArg, int intIn) {
        this(commonArg, new SubTypeOne(intIn));
    }

    public MyClass (SomeType commonArg, String stringIn) {
        this(commonArg, new SubTypeTwo(stringIn));
    }

    private MyClass (SomeType commonArg, SuperType twoIn) {
        one = commonArg;
        two = twoIn;
    }
}

啊,那是我的错。我把我的示例搞砸了一点;现在看看我写的方式。不过,你给了我一个将两个构造函数合并成一个,接受SuperType参数,并让调用者在调用之前实际构造SuperType对象的想法。我希望在调用发生的地方不要显示SuperType,但这是我能想到的最好的办法。 - Rag
容易理解。这个怎么样?它避免了允许SuperType的任何子类,避免了重复,并始终分配给两个变量。请注意,在null上的转换以避免歧义。https://gist.github.com/stickyd/4965120 - Richard Taylor

6

你需要确保在每个构造函数中都初始化了所有的final变量。我的建议是创建一个构造函数来初始化所有变量,并让其他构造函数调用该函数,如果某些字段没有给定值,则传入null或一些默认值。

例如:

public class MyClass {
    private final SomeType one;
    private final SuperType two;

    //constructor that initializes all variables
    public MyClas(SomeType _one, SuperType _two) {
        one = _one;
        two = _two;
    }

    private MyClass(SomeType _one) {
        this(_one, null);
    }

    public MyClass(SomeType _one, SubTypeOne _two) {
        this(_one, _two);
    }

    public MyClass(SomeType _one, SubTypeTwo _two) {
        this(_one, _two);
    }
}

1
你需要做的就是确保“two”被初始化。在第一个构造函数中,只需添加:
two = null;

除非你想在仅调用第一个构造函数的情况下给它赋予其他值。

您可以将最终变量初始化为 null。它只需要被初始化为“某些东西”。如果您想要两个具有非空值,则必须调用其他构造函数之一。它与 Sticky 的答案具有相同的最终结果。 - Halogen
2
但问题是,如果我在第一个构造函数中将two设置为null,那么我就无法在其他构造函数中设置它的实际值,因为它已经被设置过了。 - Rag

0

你会得到这个错误是因为如果你调用了 MyClass(SomeType oneIn)two 没有被初始化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接