關於 static 和 final 的一些理解
阿新 • • 發佈:2018-08-11
初始 標記 private 關於 mage final 統計 內部類 對象創建
1.類是加載到方法區中的
2.類是在第一次使用的時候才加載,加載之後就不會移除
練習:定義一個類,統計這個類創建對象的個數。
---恢復內容開始---
今天主要回顧一下 static 和 final 著兩個關鍵字。
1. static - 靜態 修飾符 - 用於修飾數據(變量、對象)、方法、代碼塊以及內部類。 1.1 靜態變量 用static修飾變量,稱之為靜態變量,也叫類變量。在類加載的時候加載到了方法區,並且在方法區中被賦予了默認值。靜態變量是先於對象出現的,所以習慣上是通過類名來調用靜態變量。每一個對象存儲的是這個靜態變量在方法區中的地址,所以靜態變量是被這個類的所有對象所共享的。 靜態變量能否定義到構造方法中? --- 不能。靜態變量是在類加載的時候出現,先於對象出現。構造方法在創建對象的時候執行。 註意: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{ static1.2 靜態方法 用 static 修飾的方法,稱之為靜態方法。靜態方法隨著類的加載而加載到方法區中,但是在方法區中不執行只存儲,在方法被調用的時候到棧內存執行。靜態方法先於對象存在,所以習慣上是通過類名來調用靜態方法。 main Arrays.sort(); System.arraycopy(); 靜態方法中可以定義靜態變量嗎? --- 不能 --- 靜態方法在調用的時候執行,靜態方法執行的時候裏面的變量才能初始化;靜態變量是在類加載的時候初始化。 靜態方法中能否使用 this/super? --- 不能 --- this 代表當前在活動的對象,靜態方法先於對象存在 能否在靜態方法中直接使用本類中的非靜態方法/非靜態屬性? --- 不行 靜態方法可以重載嗎? --- 可以(講重載的時候,默認都是寫的 public static ) 靜態方法可以被繼承嗎?--- 可以 靜態方法可以重寫嗎?--- 不可以 靜態方法雖然不能被重寫,但是父子類中可以存在方法簽名一致的靜態方法 --- 靜態方法的隱藏(hide) 註意:父子類中可以存在方法簽名一致的方法,要麽都是非靜態(重寫)要麽都是靜態(隱藏)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;//常量的二次賦值 } } */
---恢復內容結束---
關於 static 和 final 的一些理解