關鍵字 final 的使用小結:
-
final 可以修飾變數,被 final 修飾的變數被賦初始值之后,不能對它重新賦值,
-
final 可以修飾方法,被 final 修飾的方法不能被重寫,
-
final 可以修飾類,被 final 修飾的類不能派生子類,
被 final 修飾的成員變數必須顯式指定初始值,而且只能在如下 3 個位置指定初始值,
定義 final 實體變數時指定初始值;
-
在非靜態初始化塊中為 final 實體變數指定初始值;
-
在構造器中為 final 實體變數指定初始值,
對于普通實體變數, Java 程式可以對它執行默認的初始化,也就是將實體變數的值指定為默認的初始值 0 或 null ;但對于 final 實體變數,則必須由程顯式指定初始值,
下面程式示范了在 3 個地方對 final 實體變數進行初始化,
public class FinalDemo {
final String str1 = "直接顯式指定初始值";
final String str2 ;
final String str3 ;
{
str2 = "非靜態初始化塊中指定初始值";
}
public FinalDemo(){
str3 = "構造器中指定初始值";
}
}


import java.util.Random;
public class FinalDemo {
final String str1 = "java";
final String str2 ;
final String str3 ;
{
str2 = "java";
}
public FinalDemo(){
str3 = "java";
}
public void show(){
System.out.println(str1+str1 == "javajava");//true
System.out.println(str2+str2 == "javajava");//false
System.out.println(str3+str3 == "javajava");//false
}
public static void main(String[] args) {
final int a = 30;
final int b = 90/3; //編譯期常量,執行替換
final String c = "30";
final String str = "java";
final double d= 99.0;
final int r = new Random().nextInt(100); //運行時決定初始值
System.out.println("java30" == "java"+a); //true
System.out.println("java30" == "java"+b); //true
System.out.println("java30" == "java"+String.valueOf(a));//false
System.out.println("java30" == "java"+c); //true
System.out.println("---------------------------");
FinalDemo fd = new FinalDemo();
fd.show();
}
}
a、b、c、str 在編譯時期就確定這是個變數的值,因此它們都是“常量”, String.valueOf(a) 需要呼叫 String 方法因此編譯器無法在編譯時就確定變數值,無法執行常量替換,
上面程式中定義了 3 個 final 實體變數,但只有 str1 在定義該變數時指定了初始值,另外的 str2 、 str3 分別在非靜態初始化塊、構造器中指定初始值,因此系統不會對 str2 、 str3 執行“常量替換”,但會對 str1 執行“宏替換”,
上面程式里的 3 條粗體字代碼中只有第 1 條才會輸出 true ,因為系統會對 str1 執行“宏替換”,也就是說第 3 條粗體字代碼相當于: System.out.println ( “Java” + “Java” == “JavaJava” ) ; 上面代碼會輸出 true ,
與此類似的是,對于普通類變數,在定義時指定初始值、在靜態初始化塊中賦初始值的效果基本一樣,但對于 final 類變數而言,只有在定義 final 類變數時執指定初始值,系統才會對該 final 類變數執行“宏替換”,示例如下:
public class FinalDemo {
final static String str1 = "java";
final static String str2 ;
static{
str2 = "java";
}
public static void main(String[] args) {
System.out.println("javajava" == str1+str1); //true
System.out.println("javajava" == str2+str2); //false
}
}
上面程式中定義了 2 個 final 類變數,但只有 str2 在定義該變數時指定了初始值, str1 則在靜態初始化塊中指定初始值,因此系統不會對 str1 執行“宏替換”,但會對 str2 執行“宏替換”,上面程式里的 2 條粗體字代碼中只有第 2 條才會輸出 true ,因為系統會對 str2 執行“宏替換”,也就是說第 2 條粗體字代碼相當于: System.out.println ( “Java” + “Java” == “JavaJava” );上面代碼輸出 true ,
注意:對于運行期常量,它既可是基本資料型別,也可是參考資料型別,基本資料型別不可變的是其內容,而參考資料型別不可變的是其參考,參考所指定的物件內容是可變的,示例如下:
public class Person {
private String name;
Person(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class FinalTest {
private final String final_01 = "chenssy"; //編譯期常量,必須要進行初始化,且不可更改
private final String final_02; //構造器常量,在實體化一個物件時被初始化
private static Random random = new Random();
private final int final_03 = random.nextInt(50); //使用亂數來進行初始化
//參考
public final Person final_04 = new Person("chen_ssy"); //final指向參考資料型別
FinalTest(String final_02){
this.final_02 = final_02;
}
public String toString(){
return "final_01 = " + final_01 +" final_02 = " + final_02 + " final_03 = " + final_03 +
" final_04 = " + final_04.getName();
}
public static void main(String[] args) {
System.out.println("------------第一次創建物件------------");
FinalTest final1 = new FinalTest("cm");
System.out.println(final1);
System.out.println("------------第二次創建物件------------");
FinalTest final2 = new FinalTest("zj");
System.out.println(final2);
System.out.println("------------修改參考物件--------------");
final2.final_04.setName("chenssy");
System.out.println(final2);
}
}
------------------
Output:
------------第一次創建物件------------
final_01 = chenssy final_02 = cm final_03 = 34 final_04 = chen_ssy
------------第二次創建物件------------
final_01 = chenssy final_02 = zj final_03 = 46 final_04 = chen_ssy
------------修改參考物件--------------
final_01 = chenssy final_02 = zj final_03 = 46 final_04 = chenssy
final 修飾參考變數

public class Custom extends Person{
public void method1(){
System.out.println("Person's method1....");
}
// Cannot override the final method from person:子類不能覆寫父類的final方法
// public void method2(){
// System.out.println("Person's method2...");
// }
}


最新2020整理收集的一些高頻面試題(都整理成檔案),有很多干貨,包含mysql,netty,spring,執行緒,spring cloud、jvm、原始碼、演算法等詳細講解,也有詳細的學習規劃圖,面試題整理等,
需要獲取這些內容的朋友請加Q君樣:
756584822
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/237225.html
標籤:java
