關於 static 和 final 的一些理解
阿新 • • 發佈:2021-12-12
今天主要回顧一下 static 和 final 這兩個關鍵字。
1. static - 靜態 修飾符 - 用於修飾資料(變數、物件)、方法、程式碼塊以及內部類。 1.1 靜態變數 用static修飾變數,稱之為靜態變數,也叫類變數。在類載入的時候載入到了方法區,並且在方法區中被賦予了預設值。靜態變數是先於物件出現的,所以習慣上是通過類名來呼叫靜態變數。每一個物件儲存的是這個靜態變數在方法區中的地址,所以靜態變數是被這個類的所有物件所共享的。 靜態變數能否定義到構造方法中? --- 不能。靜態變數是在類載入的時候出現,先於物件出現。構造方法在建立物件的時候執行。 注意: 1.類是載入到方法區中的 2.類是在第一次使用的時候才載入,載入之後就不會移除 練習:定義一個類,統計這個類建立物件的個數。package cn.tedu.staticx; public class StaticExer { public static void main(String[] args) { new SDemo(); new SDemo(); new SDemo(); System.out.println(SDemo.count); } } class SDemo{ static int count = 0;//如果不用 static 則每一個物件建立的時候,都會賦值為 0 ,然後再加一次,只能是1 public SDemo(){ count++; } }
package cn.tedu.staticx; public class StaticDemo5 { public static void main(String[] args) { System.out.println(D.i); } } class D{ static int j = 5;//先將靜態變數i放入方法區,並且標記一個值為0;在初始化階段,再檢查i是否有初始值0,如果沒有初始值,則將標記值0賦值進去; //如果有初始值,則將初始值設定進去,拋棄標記值,然後順次執行靜態程式碼塊,將靜態變數i的值改為7 { j = 7; } //在類載入階段,由於i處於一個標記值狀態,所以實際上是無值的,所以此時不允許直接操作 static{ //先將靜態變數i放入方法區,並且標記一個值為0;在初始化階段,先執行靜態程式碼塊,對於i=7;並不是將7直接賦值給i;檢查i是否有初始值, //如果沒有初始值,則將標記值7賦值進去;如果有初始值則拋棄標記值,將初始值5賦值進去 i = 7; i = 9; //i -= 5;//進行運算就報錯了,類在載入的時候是分了 5 個階段:準備(載入這個類中的靜態變數並標記預設值) -> 初始化(初始化靜態變數,執行靜態程式碼塊) } static int i = 5; }1.3靜態程式碼塊 用static{ }包起來的程式碼 --- 在類載入的時候執行一次 執行順序:父類靜態 -> 子類靜態 -> 父類非靜態 -> 父類的構造方法 -> 子類非靜態 -> 子類的構造方法 2. final 修飾符 --- 修飾資料、方法以及類 final 修飾資料的時候 ---- 常量 ->定義好之後不可改變。如果 final 修飾的是基本資料型別的資料,那麼指的是實際值不可變;如果 final 修飾的引用型別的資料,那麼指的是地址不可變,但是物件中的元素或者屬性值可以改變 --- 對於成員常量要求在物件建立完成之前給值;對於靜態常量而言要求在類載入完成之前給值。 arr.length System.in System.out 注意:常量的儲存和方法區中的執行時常量池有關。 final修飾方法 --- 最終方法,能被繼承但是不可被重寫/隱藏,能被過載 final修飾類 --- 最終類 --- 不能被繼承(裡面的方法現階段也不能被重寫)System
package cn.tedu.finalx; import java.util.Arrays; public class FinalDemo1 { public static void main(String[] args) { //final int i = 9; final int i; i = 13; final int[] arr = {3,6,1,7,0}; arr[1] = 8;//並沒有報錯,因為 arr 是一個物件 -> 地址不可變 //arr = new arr[4];//報錯了,地址改變了 //arr.length = 9; //changeValue(i); System.out.println(i); expand(arr);//一開始主函式中有一個 arr 了,指向堆記憶體中的某個地址,當呼叫這個方法後,方法中的 arr 會指向這個地址,但改變後, System.out.println(arr.length);//方法中的arr指向新的地址,而主函式中的那個還是指向原來的地址(方法用完就釋放堆記憶體中的資源) } //在這個方法中並沒有將引數i定義為常量 public static void changeValue(int i){ i++; } public static void expand(int[] arr){ arr = Arrays.copyOf(arr, arr.length * 2); } } class A{ //定義成員常量 //成員常量 i 在物件完成建立之前給值 final int i = 6; int j; //靜態常量必須在類載入完成之前給值 static final int k = 0; { //i = 10; } public A(){ //i = 10; } } /*class A{ private final int i; { //i = 4; } public A(){ this(5);//是對的 //this.i = 0;也是對的,兩次呼叫是互不影響的 }//無參構造中未初始化常量 public A(int i){ this.i = i;//常量的二次賦值 } } */
---恢復內容結束---