【问题标题】:Is this "s" effectively final?这个“s”实际上是最终的吗?
【发布时间】:2016-02-11 22:32:02
【问题描述】:

这是一些示例代码(假设 Java 8)。

while (true){
    Socket s = serverSocket.accept();
    // some code here ... we don't assign anything to s again here ... 
}

s 在循环内有效吗?

【问题讨论】:

  • 我不这样做。假设我不这样做,我会询问“有效最终”。
  • @cricket_007:如果你从不那样做,那么s实际上仍然是最终的。
  • @peter.petrov:这让我有点痛苦,但这个副本回答了你的问题。在 Java 8 中,这是有效的;在 Java 7 和更早的版本中,这要复杂得多。
  • @Reimeus:“有效最终”一词甚至适用于 Java 7 吗?
  • @cricket_007,除非我弄错了,否则它基本上是 Java 8 的东西。这与 lambda 何时可以引用外部变量有关。

标签: java


【解决方案1】:

假设s 没有在其声明之后被分配,那么是的,s 是“有效的最终”,根据JLS, Section 4.12.4,它定义了它,在你的情况下:

某些未声明为最终的变量被视为实际上是最终的

  • 如果满足以下所有条件,则声明符具有初始化程序(第 14.4.2 节)的局部变量实际上是最终的

    • 它没有被声明为final

    • 它永远不会出现在赋值表达式的左侧(第 15.26 节)。 (请注意,包含初始化程序的局部变量声明符不是赋值表达式。)

    • 它永远不会作为前缀或后缀递增或递减运算符的操作数出现(第 15.14 节、第 15.15 节)。

  • 如果满足以下所有条件,则声明符缺少初始化程序的局部变量实际上是最终变量:

    • 它没有被宣布为最终的。

    • 当它出现在赋值表达式的左侧时,它肯定是未赋值的,并且在赋值之前也不是肯定赋值的;也就是说,它在赋值表达式的右侧(第 16 节(定义赋值))之后肯定是未赋值的,也不是肯定赋值的。

    • 它永远不会作为前缀或后缀递增或递减运算符的操作数出现。

您只在声明时分配s,并且作为一个对象,它不能是递增或递减运算符的操作数,因此它实际上是最终的。

它还说明了一个变量在另一种情况下可以是有效的final,如果它在声明时没有赋值,只要它只赋值一次,它肯定不是在声明之前赋值,它肯定是在声明之后赋值。

此外,在该部分的末尾,它指出:

如果一个变量实际上是final,则在其声明中添加 final 修饰符不会引入任何编译时错误。相反,如果删除了 final 修饰符,则在有效程序中声明为 final 的局部变量或参数将变为有效的最终变量。

您应该能够明确地使用final 而不会导致编译器错误。如果是这样,它实际上是最终的。

【讨论】:

  • 嗯。您引用的两个部分似乎在 int i; i = 3; 之类的情况下存在分歧。前者似乎说 i 实际上是 not 最终的(因为它的声明器没有初始化器,并且它确实出现在赋值语句的左侧),而后者似乎说i 有效的最终(因为final int i; i = 3; 是完全有效的)。规范中的其他内容是否解决了这种明显的差异?
  • 为简洁起见,在拆分声明/单个赋值的情况下,我留下了它可以成为有效最终结果的另一种方式的引用。我会把它包括在内...
  • 啊,我明白了;谢谢。我认为你喜欢简洁是对的。也许只是将第二个要点保留为“声明符缺少初始化程序的局部变量实际上是 final if [...]”——也就是说,将“if”一词之后的所有内容都替换为“[...]”? (哦,顺便说一下 +1。)
猜你喜欢
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多