java-fianl關鍵字

前言

該篇文章講了關於java final 關鍵字的一些內容 , 大部分內容參考 : https://www.cnblogs.com/dolphin0520/p/3736238.html

概述

final 可以修飾 :

  • 變量
  • 方法

final 的主要作用有 :

  • final 變量一旦被初始化賦值之後,就不能再被賦值了。
  • final 引用不能被更改
  • final 修飾類時, 該類不能被繼承
  • final 修飾方法, 該方法不會被子類重寫

修飾

修飾類

可以看到加了 final 的類不能給繼承
img

修飾方法

下面這段話摘自《Java編程思想》第四版第143頁:

  “使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實現版本中,會將final方法轉爲內嵌調用。但是如果方法過於龐大,可能看不到內嵌調用帶來的任何性能提升。在最近的Java版本中,不需要使用final方法進行這些優化了。“

修飾變量

來自海子的文章 :
  對於一個final變量,如果是基本數據類型的變量,則其數值一旦在初始化之後便不能更改;如果是引用類型的變量,則在對其初始化之後便不能再讓其指向另一個對象。

1. 作爲變量

img

2. 作爲方法形參

img

如上面的代碼 , 傳參數到 changeValue並沒有限制實參(即 i ) , 而在 changeValue方法內形參就受到了限制 .

3. 作爲內部類參數

public class Test {
    public static void main(String[] args)  {
         
    }
     
    public void test(final int b) {
        final int a = 10;
        new Thread(){
            public void run() {
                System.out.println(a);
                System.out.println(b);
            };
        }.start();
    }
}

這個地方內部類使用了 a ,必須使用 final修飾 ,原因就是爲了防止 a 這個變量在內部類對象被修改了 . 具體的我們在內部類後面的文章詳細分析 .

深入 final

    這個章節來自 : https://www.cnblogs.com/dolphin0520/p/3736238.html , 非原創 

1.類的final變量和普通變量有什麼區別?
  當用final作用於類的成員變量時,成員變量(注意是類的成員變量,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值,而且final變量一旦被初始化賦值之後,就不能再被賦值了。
  那麼final變量和普通變量到底有何區別呢?下面請看一個例子:

public class Test {
    public static void main(String[] args)  {
        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
        System.out.println((a == c));
        System.out.println((a == e));
    }
}
  
true
false

大家可以先想一下這道題的輸出結果。爲什麼第一個比較結果爲true,而第二個比較結果爲fasle。這裏面就是final變量和普通變量的區別了,當final變量是基本數據類型以及String類型時,如果在編譯期間能知道它的確切值,則編譯器會把它當做編譯期常量使用。也就是說在用到該final變量的地方,相當於直接訪問的這個常量,不需要在運行時確定。這種和C語言中的宏替換有點像. 因此在上面的一段代碼中,由於變量b被final修飾,因此會被當做編譯器常量,所以在使用到b的地方會直接將變量b 替換爲它的 值。而對於變量d的訪問卻需要在運行時通過鏈接來進行。想必其中的區別大家應該明白了,不過要注意,只有在編譯期間能確切知道final變量值的情況下,編譯器纔會進行這樣的優化,比如下面的這段代碼就不會進行優化:

public class Test {
    public static void main(String[] args)  {
        String a = "hello2"; 
        final String b = getHello();
        String c = b + 2; 
        System.out.println((a == c));
 
    }
     
    public static String getHello() {
        return "hello";
    }
}
  這段代碼的輸出結果爲false。

final 常見問題

final 與 static

static作用於成員變量用來表示只保存一份副本,而final的作用是用來保證變量不可變。

public class Test {
    public static void main(String[] args)  {
        MyClass myClass1 = new MyClass();
        MyClass myClass2 = new MyClass();
        System.out.println(myClass1.i);
        System.out.println(myClass1.j);
        System.out.println(myClass2.i);
        System.out.println(myClass2.j);
 
    }
}
 
class MyClass {
    public final double i = Math.random();
    public static double j = Math.random();
}

運行這段代碼就會發現,每次打印的兩個j值都是一樣的,而i的值卻是不同的 , 從這裏就可以看出兩者的區別了, (static 變量和類優先於普通類提前加載)

被final修飾的引用變量指向的對象的內容可變嗎?

public class Test {
    public static void main(String[] args)  {
        final MyClass myClass = new MyClass();
        System.out.println(++myClass.i);
 
    }
}
 
class MyClass {
    public int i = 0;
}

public class Test {
    public static void main(String[] args)  {
        MyClass myClass = new MyClass();
        StringBuffer buffer = new StringBuffer("hello");
        myClass.changeValue(buffer);
        System.out.println(buffer.toString());
    }
}
 
class MyClass {
     
    void changeValue(final StringBuffer buffer) {
        buffer.append("world");
    }
}

這段代碼是可以編譯運行的也就是說 final 限制的是對象的指針 , 而指針所指的對象裏的內容是發生更改的.

補充

  1. java採用的是值傳遞,對於引用變量,傳遞的是引用的值,對於基本類型的變量,相當於直接將變量進行了拷貝。
  2. 假如使用 xxMethod(final int b) , 那麼 b 只能是讀取, 不能修改 , 如果 b 是對象,則是不能改變引用

參考內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章