我正在查看有关最终变量的另一个问题,并注意到您可以声明最终变量而不初始化它们(一个空白的最终变量)。是否有理由这样做是可取的,什么时候有利?
9 回答
这对于创建不可变对象很有用:
public class Bla {
private final Color color;
public Bla(Color c) {this.color = c};
}
Bla 是不可变的(一旦创建,它就不能改变,因为颜色是最终的)。但是您仍然可以通过用各种颜色构建它们来创建各种 Blas。
例如,另请参阅此问题。
编辑
也许值得补充一点,“空白决赛”在 Java 中具有非常特殊的含义,这似乎在评论中造成了一些混乱 - 参见Java 语言规范 4.12.4:
空白 final 是一个 final 变量,其声明缺少初始化程序。
然后,您必须在构造函数中分配该空白最终变量。
当您在检测对象之前不知道值是什么时,您可以这样做,它只需要在其构造函数中分配一个值。
这就是制作不可变对象的方式,它在构建器模式中使用。
class Builder{
final BuilderContext context;
private Builder(BuilderContext context){
this.context=context;
}
public static Builder New(){
return new Builder(new BuilderContext());
}
空白最终变量必须在构造函数中“某处”分配。一个相当构造的例子:
public class Test {
final int sign;
public Test(String upDown) {
if (upDown.equals("up")) {
sign = +1;
} else {
sign = -1;
}
}
}
一种情况可能是当您有一个要声明为 final 的字段,但其赋值可能会引发异常,并且您希望能够在发生这种情况时采取措施:
class A {
final URLConnection conn;
A(String url) {
try {
this.conn = new URL(url).openConnection();
} catch (IOException | MalformedURLException e) {
// Maybe this isn't fatal, so just handle the Exception
// here and move on happily
}
}
}
在方法中使用一个空白的 final 变量来显示所有使用该变量的代码路径只分配该变量一次(或抛出异常)。Java 编译器将保证在使用之前分配一个空白的最终变量。
某些方法中的示例代码:
final Foo foo;
if (condition1()) {
foo = makeFoo(1);
} else if (condition2()) {
throw new BarException();
} else {
foo = makeFoo(-1);
}
...
blahBlahBlah(foo);
使用空白的最终变量会告诉代码的下一位读者,编译器保证有人在调用 blahBlahBlah(foo) 之前分配了 foo。
该问题询问“空白最终变量”。讨论“空白最终字段”是一个不同的讨论,并且本身就很有趣。
注意到您可以
final
在不初始化变量的情况下声明变量
您必须稍后初始化它(例如在构造函数中),这样它就不会保持为空。
来自维基百科
在 Java 1.1 中引入的空白 final 是一个 final 变量,它的声明缺少初始化器。空白期末只能分配一次,并且在分配发生时必须取消分配。为了做到这一点,Java 编译器会运行一个流分析,以确保每次赋值给一个空白的 final 变量时,该变量在赋值之前肯定是未赋值的;否则会发生编译时错误。
通常,Java 编译器将确保在为其分配值之前不使用空白 final,并且一旦分配了一个值,现在的 final 变量就不能重新分配另一个值。
我发现它们对于派生状态的方法非常有用。它提供了一个干净的执行路径,并确保状态变量被分配一次且仅一次。例如:
public boolean isEdible() {
final boolean edible;
if (vegetable) {
edible = true;
} else if (animal) {
if (vegetarian) {
edible = false;
} else {
edible = true;
}
}
System.out.println("Is edible: " + edible);
return edible;
}