1. 程式人生 > >為什麼必須是final的呢?

為什麼必須是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);
    }
}

這個匿名子類會被編譯成一個單獨的類,反編譯的結果是這樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TryUsingAnonymousClass$1
        
            
           

相關推薦

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

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

為什麼必須final

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

為什麼介面要規定成員變數必須是public static final?

在interface裡面的變數都是public static final 的。所以你可以這樣寫: public static final int i=10; 或則 int i=10;(可以省略掉一部分) 注意在宣告的時候要給變數賦予初值,而抽象類則不用初始化! 解釋:

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

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

為什麽局部內部類訪問外邊的局部變量必須final

下載 out title ble 類型 cannot www. 錯誤 。。 6.局部內部類訪問外邊的局部變量時,此變量必須為final類型 (視頻下載) (全部書籍)馬克-to-win:由於技術方面的限制,java的設計者們做出如下語法規定:局部內部類訪問外邊的局部變量時,

匿名類訪問區域性變數時,為什麼區域性變數必須final

匿名內部類就是在物件的方法體內部定義的類。我們都知道方法中的匿名內部類是能夠訪問同一個方法中的區域性變數的,但是為什麼區域性變數要加上一個final呢?  原因就是因為匿名內部類物件的生命週期可能會超過區域性變數的生命期。區域性變數的生命週期是當該方法被呼叫時,該方法中的區

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

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

關於為什麼jdk 8以前匿名內部類引數必須final型別的問題

我們先來看一段程式碼   public class Hello {     public static void main(String[] args) {         String str=

Java匿名內部類中使用外部類方法的形參或區域性變數必須宣告為final

 對於這個問題,首先我們應該明確的一點是對於匿名內部類,它可能引用三種外部變數:外部類的成員變數外部方法或作用域內的區域性變數外部方法的引數而第一種變數是不需要宣告為final的,但後兩種是需要宣告為final的。那這是為什麼呢?不急,我們首先來看第一個知識點。知識點一,匿名內部類同所有類一

區域性內部類引用外部類中的區域性變數必須final屬性的!

如例中所示,聲明瞭一個區域性內部類TimerPrint,這個類中的方法引用了一個區域性變數testTxt,必須宣告為final!!why? 邏輯上:因為該內部類出現在一個方法的內部,但實際編譯時,內部類編譯為Outer$1TimerPrint.class,這說明,外

內部類中引用的變數必須要宣告為final的原因

查了下看到有人說原因如下: 區域性匿名類在原始碼編譯後也是要生成對應的class檔案的(一般會是A$1.class這種形式的檔案),那麼這個二進位制檔案是獨立於其外圍類(A.class)的,就是說它無法知道A類中方法的變數。但是A$1.class又確實要訪問A類對應方法的區域性變數的值。。。怎麼辦呢?

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

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

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

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

為什麼匿名內部類用到的變數必須定為final

如果說匿名內部類無法被繼承,那麼也只能說匿名內部類是final的。如果一個類是final的,那麼所有屬於這個類的方法是final的,但它的成員變數並不是。而且被final的變數還是外部類的,外部類沒有必要不讓自己修改自己的變數的值。上述情況其實只發生在內部類引用的變數不是成員

為什麼介面中的屬性必須用public static final修飾?

public: 使介面的實現類可以使用這個常量 static:static修飾就表示它屬於類的,隨的類的載入而存在的,如果是非static的話,     就表示屬於物件的,只有建立物件時才有它,而介面是不能建立物件的,所以     介面的常量必須定義為static fina

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

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

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

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

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

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

接口裡定義的成員變數必須是public static final型別

在interface裡面的變數都是public static final 的。所以你可以這樣寫:   public static final int i=10;   或則   int i=10;(可以省略掉一部分)   注意在宣告的時候要給變數賦予初值   解釋:   首先

為什vue元件中的data必須是函式?

類比引用資料型別 Object是引用資料型別,如果不用function 返回,每個元件的data 都是記憶體的同一個地址,一個數據改變了其他也改變了; 關於JS中的資料型別: javascipt只有函式構成作用域(注意理解作用域,只有函式的{}構成作用域,物件的{}以及 if(){