Java中方法中的final变量

32

可能重复:
为什么在Java中标记局部变量和方法参数为“final”?

我在检查一些Java代码,尽管我不是很擅长Java,但至少了解一些像封闭类、只读字段和不可重写方法这样的final的作用,不过这看起来对我来说有些奇怪,在方法中声明一个final变量:

private static void queryGoogleBooks(JsonFactory jsonFactory, String query) throws Exception {
    // Set up Books client.
    final Books books = Books.builder(new NetHttpTransport(), jsonFactory)
        .setApplicationName("Google-BooksSample/1.0")
        .setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
          @Override
          public void initialize(JsonHttpRequest request) {
            BooksRequest booksRequest = (BooksRequest) request;
            booksRequest.setKey(ClientCredentials.KEY);
          }
        })
        .build();
请问在这个上下文中,final 是什么意思呢?
以下是完整的代码: http://code.google.com/p/google-api-java-client/source/browse/books-cmdline-sample/src/main/java/com/google/api/services/samples/books/cmdline/BooksSample.java?repo=samples
5个回答

36

这段代码简单地使本地变量books成为不可变的。这意味着它将永远是一个对创建和构建同一Book对象的引用,并且不能被更改以指向另一个对象或空值。

可以从访问器调用序列中看出,Book对象本身仍然是可变的。只有对它的引用是不可变的。


1
值得注意的是,Books指向的对象是可变的。 - Doug Moscrop
1
@Doug:没错 - 我刚刚把那个加到我的答案里了。谢谢。 - BoltClock
+1 然后(虽然只是沧海一粟..) - Doug Moscrop

12
在这种情况下,final Books books 简单地意味着 books 必须恰好分配一次值。
我喜欢像这样使用 final 关键字,因为它显示了变量的意图,当查看代码时,我发现这是有价值的信息,因为它从情况中删除了另一个变量,可以说是如此。
如果我没有将一个变量标记为 final,那么它会凸显出需要特别留意它,因为它很快就要改变值了。这些信息在例如通过调试器步进代码或者重构和移动代码时非常有帮助。
更多关于所有事情的 final 的阅读内容: 关于 final 关键字的最终结论

在这个上下文中,final有更多的意义。 - user166390
+1 给链接,非常好的解释! - NguyenDat

4

这同样使得变量引用成为只读的。通常,这是为了保护代码不会意外地修改一个不能改变的变量。


在这个上下文中,“final”有更多的含义。 - user166390

1

我相信这只是意味着在方法中变量books以后不能被覆盖。


1

这段代码使用了匿名类JsonHttpRequestInitializer,其中引用了方法queryGoogleBooks中的局部变量。在这种情况下的问题是,queryGoogleBooks方法可能会在JsonHttpRequestInitializer的初始化方法完成之前返回,这可能会清除变量并导致JsonHttpRequestInitializer的初始化方法失败。因此,在这种类型的情况下,需要将变量声明为final。有关更多详细信息,请参见:

无法在不同方法中定义的内部类中引用非最终变量


1
匿名类没有引用变量books。如果有的话,编译时会出现错误,因为匿名类是在变量初始化之前创建的。 - Michael Krussel

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