13

我正在查看有关最终变量的另一个问题,并注意到您可以声明最终变量而不初始化它们(一个空白的最终变量)。是否有理由这样做是可取的,什么时候有利?

4

9 回答 9

29

这对于创建不可变对象很有用:

public class Bla {
    private final Color color;

    public Bla(Color c) {this.color = c};

}

Bla 是不可变的(一旦创建,它就不能改变,因为颜色是最终的)。但是您仍然可以通过用各种颜色构建它们来创建各种 Blas。

例如,另请参阅此问题

编辑

也许值得补充一点,“空白决赛”在 Java 中具有非常特殊的含义,这似乎在评论中造成了一些混乱 - 参见Java 语言规范 4.12.4

空白 final 是一个 final 变量,其声明缺少初始化程序。

然后,您必须在构造函数中分配该空白最终变量。

于 2012-07-05T13:55:33.897 回答
5

类的最终属性必须在创建对象之前分配一个值。因此,您可以为它们赋值的最后一点是构造函数。

这通常用于不可变对象

 public class Foo {

  private final Bar bar;

  public Foo(Bar bar) {
    this.bar = bar;
  }

  public Bar getBar() {
   return new Bar(bar);
 } 
}

维基对此有何评论

防御性抄袭。

于 2012-07-05T13:56:44.370 回答
2

当您在检测对象之前不知道值是什么时,您可以这样做,它只需要在其构造函数中分配一个值。

这就是制作不可变对象的方式,它在构建器模式中使用。

class Builder{
    final BuilderContext context;

    private Builder(BuilderContext context){
        this.context=context;
    }       

    public static Builder New(){
        return new Builder(new BuilderContext());
    }
于 2012-07-05T13:55:44.283 回答
1

空白最终变量必须在构造函数中“某处”分配。一个相当构造的例子:

public class Test {
    final int sign;
    public Test(String upDown) {
        if (upDown.equals("up")) {
            sign = +1;
        } else {
            sign = -1;
        }
    }
}
于 2012-07-05T13:59:10.273 回答
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
    }
  }
}
于 2012-07-05T14:07:45.347 回答
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。

该问题询问“空白最终变量”。讨论“空白最终字段”是一个不同的讨论,并且本身就很有趣。

于 2014-05-19T18:12:06.480 回答
0

注意到您可以final在不初始化变量的情况下声明变量

您必须稍后初始化它(例如在构造函数中),这样它就不会保持为空。

于 2012-07-05T13:56:31.923 回答
0

来自维基百科

在 Java 1.1 中引入的空白 final 是一个 final 变量,它的声明缺少初始化器。空白期末只能分配一次,并且在分配发生时必须取消分配。为了做到这一点,Java 编译器会运行一个流分析,以确保每次赋值给一个空白的 final 变量时,该变量在赋值之前肯定是未赋值的;否则会发生编译时错误。

通常,Java 编译器将确保在为其分配值之前不使用空白 final,并且一旦分配了一个值,现在的 final 变量就不能重新分配另一个值。

于 2012-07-05T13:57:21.027 回答
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;
}
于 2018-03-26T21:21:57.010 回答