我正在查看关于最终变量的另一个question,并注意到您可以声明最终变量而不初始化它们(blank final变量)。有没有理由这样做,什么时候有利?
答案 0 :(得分:27)
这对于创建不可变对象非常有用:
public class Bla {
private final Color color;
public Bla(Color c) {this.color = c};
}
Bla是不可变的(一旦创建,它就不能改变,因为颜色是最终的)。 但你仍然可以通过用各种颜色构建它们来创建各种Blas。
例如,另请参阅this question。
编辑
也许值得补充的是,“空白决赛”在Java中具有非常特殊的含义,这似乎在评论中引起了一些混淆 - 参见Java Language Specification 4.12.4:
空白决赛是一个最终变量,其声明缺少初始值。
然后,您必须在构造函数中分配该空白最终变量。
答案 1 :(得分:5)
类的final属性必须在创建对象之前指定一个值。所以你可以为它们赋值的最后一点是构造函数。
这经常用于immutable objects。
public class Foo {
private final Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
public Bar getBar() {
return new Bar(bar);
}
}
答案 2 :(得分:2)
当你不知道在Object的检测之前它将是什么值时你可以这样做,它只需要在它的构造函数中赋值。
这是immutable objects的制作方法,它在构建器模式中使用。
class Builder{
final BuilderContext context;
private Builder(BuilderContext context){
this.context=context;
}
public static Builder New(){
return new Builder(new BuilderContext());
}
答案 3 :(得分:1)
必须在构造函数中的“某处”指定空白的最终变量。一个相当构造的例子:
public class Test {
final int sign;
public Test(String upDown) {
if (upDown.equals("up")) {
sign = +1;
} else {
sign = -1;
}
}
}
答案 4 :(得分:1)
有一种情况可能是你有一个你要宣布最终的字段,但是它的分配可能会引发异常而你希望能够在发生这种情况时采取行动:
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
}
}
}
答案 5 :(得分:1)
在方法中使用空白的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。
问题是“空白的最终变量”。讨论“空白的最终字段”是一个不同的讨论,并且本身很有趣。
答案 6 :(得分:0)
注意到您可以在不初始化的情况下声明
final
个变量
您必须稍后对其进行初始化(例如在构造函数中),以便它不会保持为空。
答案 7 :(得分:0)
在Java 1.1中引入的空白final是一个最终变量,其声明缺少初始化器。空白最终版只能分配一次,并且在分配发生时必须取消分配。为了做到这一点,Java编译器运行流分析以确保对于空白最终变量的每个赋值,在赋值之前肯定未赋值变量;否则会发生编译时错误。
通常,Java编译器将确保在为其分配值之前不使用空白final,并且一旦分配了值,则现在的final变量不能重新分配另一个值。
答案 8 :(得分:0)
我发现它们对于派生状态的方法非常有用。它提供了一个干净的执行路径,并确保状态变量只分配一次。例如:
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;
}