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

關於 static 和 final 的一些理解

初始 標記 private 關於 mage 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;//常量的二次賦值
    }
}

*/

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

關於 static 和 final 的一些理解