1. 程式人生 > >Java內部類訪問外部物件為什麼必須是final的呢?

Java內部類訪問外部物件為什麼必須是final的呢?

一個謎團

如果你用過類似guava這種“偽函數語言程式設計”風格的library的話,那下面這種風格的程式碼對你來說應該不陌生:

1
2
3
4
5
6
7
8
9
public void tryUsingGuava() {
    final int expectedLength = 4;
    Iterables.filter(Lists.newArrayList("123", "1234"), new Predicate<String>() {
        @Override
        public boolean apply(String str
) {
return str.length() == expectedLength; } }); }

這段程式碼對一個字串的list進行過濾,從中找出長度為4的字串。看起來很是平常,沒什麼特別的。

但是,宣告expectedLength時用的那個final看起來有點扎眼,把它去掉試試:

error: local variable expectedLength is accessed from within inner class; needs to be declared final

結果Java編譯器給出瞭如上的錯誤,看起來匿名內部類只能夠訪問final的區域性變數。但是,為什麼呢?其他的語言也有類似的規定嗎?

在開始用其他語言做實驗之前我們先把問題簡化一下,不要再帶著guava了,我們去除掉噪音,把問題歸結為:

為什麼Java中的匿名內部類只可以訪問final的區域性變數呢?其他語言中的匿名函式也有類似的限制嗎?

Scala中有類似的規定嗎?

1
2
3
4
5
6
7
8
9
10
11
12
  def tryAccessingLocalVariable {
    var number = 123
    println(number)
    var lambda = () => {
      number = 456
      println(number)
    }
lambda.apply() println(number) }

上面的Scala程式碼是合法的,number變數是宣告為var的,不是val(類似於Java中的final)。而且在匿名函式中可以修改number的值。

看來Scala中沒有類似的規定

C#中有類似的規定嗎?

1
2
3
4
5
6
7
8
9
10
11
12
13
public void tryUsingLambda ()
{
  int number = 123;
  Console.WriteLine (number);
  Action action = () => {
      number = 456;
      Console.WriteLine (number);
  };
  action ();
  Console.WriteLine (number);
}

這段C#程式碼也是合法的,number這個區域性變數在lambda表示式內外都可以訪問和賦值。

看來C#中也沒有類似的規定

分析謎團

三門語言中只有Java有這種限制,那我們分析一下吧。先來看一下Java中的匿名內部類是如何實現的:

先定義一個介面:

1
2
3
public interface MyInterface {
    void doSomething();
}

然後建立這個介面的匿名子類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TryUsingAnonymousClass {
    public void useMyInterface() {
        final Integer number = 123;
        System.out.println(number);
        MyInterface myInterface = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println(number);
            }
        };
        myInterface.doSomething();
        System.out.println(number);
    }
}

相關推薦

Java部類訪問外部物件為什麼必須final

一個謎團 如果你用過類似guava這種“偽函數語言程式設計”風格的library的話,那下面這種風格的程式碼對你來說應該不陌生: 1 2 3 4 5 6 7 8 9 public void tryUsingGuava() { final int expectedLength = 4;

為什麼java部類訪問區域性變數必須宣告為final

先丟擲讓我疑惑了很久的一個問題 程式設計時,線上程中使用區域性變數時候經常編譯器會提示:區域性變數必須宣告為final package test;   publicclass ThreadTest {       publicvoid function(Stri

Java部類訪問區域性變數時的final問題

JAVA用了也快三年了,內部類訪問區域性變數的情況也沒少遇到。也一直知道要給變數加個final修飾符,不然通過不了編譯。但一直也沒深究過為什麼要加。昨天好奇的上網查了下,並翻閱了下相關的書籍(Core Java 8th),終於算是搞明白了,在這裡簡單說明下。 說先我們來

區域性部類訪問外部變數為什麼需要使用final修飾

因為生命週期的原因。方法中的區域性變數,方法結束後這個變數就要釋放掉,final保證這個變數始終指向一個物件。首先,內部類和外部類其實是處於同一個級別,內部類不會因為定義在方法中就會隨著方法的執行完畢而跟隨者被銷燬。問題就來了,如果外部類的方法中的變數不定義final,那麼

Accessing Outside Variables with the Final Keyword部類訪問外部變數

Sometimes you want to access information available outside of the inner class. Consider the following example. You’ve got a screen with

java部類例項化物件

package com.lzcc.oop.testpolymorphism; /** * 多型測試 * * @author 包子 * */ public class Person {

Java 部類訪問格式

訪問格式: 1,當內部類定義在外部類的成員位置上,而且非私有,可以在外部其他類中。 可以直接建立內部類物件。 格式外部類名.內部類名  變數名 = 外部類物件.內部類物件;Outer.Inner in = new Outer().new Inner(); 2,當內部類在成員

Java部類訪問規則

訪問格式: 1 、當內部類定義在外部類的成員位置上,而且非私有,可以在外部其他類中,直接建立內 部類物件。 格式為:外部類名 . 內部類名變數名 =  外部物件 . 內部物件; Outer.Inner in = new Outer().new Inner();  靜態內部類: 2 、當內部類

Java進階——Java 區域性部類訪問區域性變數為什麼必須final關鍵字

Java 區域性內部類訪問區域性變數為什麼必須加final關鍵字 疑問 在Java中,區域性內部類如果呼叫了方法中的變數,那麼該變數必須申明為final型別,如果不申明,則編譯就會出錯。 這裡的內部類指的是方法內部類或匿名內部類,不包含靜態內部類和成員內部類

Java部類引用外部類中的局部變量為何必須final問題解析

lib soft 編譯器 art http word tail ace 軟件 今天編寫一個多線程程序,發現在方法內定義內部類時,如果內部類調用了方法中的變量,那麽該變量必須申明為final類型,百思不得其解,後來想到應該是生命周期的原因,因為方法內定義的變量是局部變量,

java部類訪問的區域性變數為什麼要加final

如果我們在一個類中宣告一個內部類,在這個內部類中訪問了原來類中的區域性變數,那麼這個區域性變數必須在原來的類中宣告成final,如圖: class A { final int a=1;; class B { int b=a; } } 這是為什麼呢? 答案是,因為在原

java:面向物件-區域性部類訪問區域性變數的問題

* 區域性內部類訪問區域性變數必須用final修飾* 區域性內部類在訪問他所在方法中的區域性變數必須用final修飾,為什麼? 因為當呼叫這個方法時,區域性變數如果沒有用final修飾,他的生命週期和方

部類訪問區域性變數的時候,為什麼變數必須加上final修飾

這裡的區域性變數就是在類方法中的變數,能訪問方法中變數的類當然也是區域性內部類了。 我們都知道,區域性變數在所處的函式執行完之後就釋放了,但是內部類物件如果還有引用指向的話它是還存在的。例如下面的程式碼: class Outer{

java部類引用外部類中的變數 必須final

@Test//資料庫連線池DBCPpublic void testDBCP(){//建立連線池BasicDataSource ds=new BasicDataSource();//給連線池新增必要的屬性//可以將這些屬性去掉set首字母小寫,寫在.properties檔案中ds.setUsername("ro

Java部類詳解 及 區域性部類和匿名部類只能訪問區域性final變數的原因

說起內部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫程式碼時可能用到的場景不多,用得最多的是在有事件監聽的情況下,並且即使用到也很少去總結內部類的用法。今天我們就來一探究竟。下面是本文的目錄大綱:   一.內部類基礎   二.深入理解內部類   三.內部類的使用場景和好處   

Java部類引用外部類中的區域性變數為何必須final問題解析

       今天編寫一個多執行緒程式,發現在方法內定義內部類時,如果內部類呼叫了方法中的變數,那麼該變數必須申明為final型別,百思不得其解,後來想到應該是生命週期的原因,因為方法內定義的變數是區域性變數,離開該方法,變數就失去了作用,也就會自動被消除,而內部類卻不會

java部類訪問區域性變數為什麼要定義區域性變數為final

因為方法內定義的變數是區域性變數,離開該方法,變數就失去了作用,也就會自動被消除,而內部類卻不會離開它所在方法就失去作用,它有更廣的生命週期,下面通過一個例項加以說明: 如例中所示,在外部類Outer中聲明瞭一個內部類TimerPrint,這個類中的方法引用了方法start

區域性變數被部類訪問必須final修飾的問題

今天隨手寫了點東西,又遇到了這個問題,就是在當內部類想要訪問區域性變數的時候 ,Java就要求該區域性變數必須用final關鍵字進行修飾。之前寫程式的時候經常遇到這樣的問題,當時只是奔著快點結局問題的目的也沒仔細的思考它本質的原因。 但是我想Java如此的設計肯定有其目的,

Java部類的使用小結 形參為什麽要用final

trac som 調用 匿名內部類 事情 ani 如果 method 方法 部類是指在一個外部類的內部再定義一個類。類名不需要和文件夾相同。 *內部類可以是靜態static的,也可用public,default,protected和private修飾。(而外部頂級類即類名和

Java部類final關鍵字詳解

修飾 tor oca 修飾符 key eight 標識 cal ner 閱讀目錄 一、內部類的幾種創建方法: 二、神馬是內部類? 三、最後來說說final關鍵字: 回到頂部 一、內部類的幾種創建方法: 1、成員內部類 1 2 3 4 5 6 cl