1. 程式人生 > 其它 >關於 static 和 final 的一些理解

關於 static 和 final 的一些理解

今天主要回顧一下 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++;
    }
}
  1.2 靜態方法 用 static 修飾的方法,稱之為靜態方法。靜態方法隨著類的載入而載入到方法區中,但是在方法區中不執行只儲存,在方法被呼叫的時候到棧記憶體執行。靜態方法先於物件存在,所以習慣上是通過類名來呼叫靜態方法。 main Arrays.sort(); System.arraycopy(); 靜態方法中可以定義靜態變數嗎? --- 不能 --- 靜態方法在呼叫的時候執行,靜態方法執行的時候裡面的變數才能初始化;靜態變數是在類載入的時候初始化。 靜態方法中能否使用 this/super? --- 不能 --- this 代表當前在活動的物件,靜態方法先於物件存在 能否在靜態方法中直接使用本類中的非靜態方法/非靜態屬性? --- 不行 靜態方法可以過載嗎? --- 可以(講過載的時候,預設都是寫的 public static ) 靜態方法可以被繼承嗎?--- 可以 靜態方法可以重寫嗎?--- 不可以 靜態方法雖然不能被重寫,但是父子類中可以存在方法簽名一致的靜態方法 --- 靜態方法的隱藏(hide) 注意:父子類中可以存在方法簽名一致的方法,要麼都是非靜態(重寫)要麼都是靜態(隱藏)
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;//常量的二次賦值
    }
}

*/

---恢復內容結束---