天天看點

【java筆記】java中static/final/abstract關鍵字的辨析

1. static關鍵字

static關鍵字在java中的主要用來修飾變量、方法名和形成靜态代碼塊。

(1) 靜态變量

  • 變量可以分為執行個體變量和靜态變量
  • 被static修飾的屬性(變量)被成為靜态變量(類變量),其不依賴于類的特定執行個體,而是被類的所有執行個體所共享
  • 在靜态變量所在的類中,可以通過直接通路、類名通路或類的執行個體方法等進行方法,其他類中可以使用

    類名.靜态變量

    來使用
  • 靜态變量是可以修改的(差別于final)
public class StaticVar {
    public static String str1 = "Hello";
    public static void main(String[] args) {
        String str2 = "World!";
        // 直接通路str1
        String accessVar1 = str1+str2;
        System.out.println("第 1 次通路靜态變量,結果為:"+accessVar1);
        // 通過類名通路str1
        String accessVar2 = StaticVar.str1+str2;
        System.out.println("第 2 次通路靜态變量,結果為:"+accessVar2);
        // 通過對象svt1通路str1
        StaticVar svt1 = new StaticVar();
        svt1.str1 = svt1.str1+str2;
        String accessVar3 = svt1.str1;
        System.out.println("第3次訪向靜态變量,結果為:"+accessVar3);
        // 通過對象svt2通路str1
        StaticVar svt2 = new StaticVar();
        String accessVar4 = svt2.str1+str2;
        System.out.println("第 4 次通路靜态變量,結果為:"+accessVar4);
    }
}
           

(2) 靜态方法

  • 被static修飾的方法被稱為靜态方法(類方法),其他的被稱為執行個體方法
  • 靜态方法不需要通過其所屬類的執行個體就可以被調用,是以靜态方法中不能使用this和super關鍵字,也不能直接通路所屬類的執行個體變量和執行個體方法,但可以通路所屬類的靜态變量和靜态方法
  • 通路靜态方法時,可以直接通路,也可以通過類名來通路,還可以通過執行個體化對象來通路
public class StaticMethod {
    public static int count = 1;    // 定義靜态變量count
    public int method1() {    
        // 執行個體方法method1
        count++;    // 通路靜态變量count并指派
        System.out.println("在靜态方法 method1()中的 count="+count);    // 列印count
        return count;
    }
    public static int method2() {    
        // 靜态方法method2
        count += count;    // 通路靜态變量count并指派
        System.out.println("在靜态方法 method2()中的 count="+count);    // 列印count
        return count;
    }
    public static void PrintCount() {    
        // 靜态方法PrintCount
        count += 2;
        System.out.println("在靜态方法 PrintCount()中的 count="+count);    // 列印count
    }
    public static void main(String[] args) {
        StaticMethod sft = new StaticMethod();
        // 通過執行個體對象調用執行個體方法
        System.out.println("method1() 方法傳回值 intro1="+sft.method1());
        // 直接調用靜态方法
        System.out.println("method2() 方法傳回值 intro1="+method2());
        // 通過類名調用靜态方法,列印 count
        StaticMethod.PrintCount();
    }
}public class StaticMethod {
    public static int count = 1;    // 定義靜态變量count
    public int method1() {    
        // 執行個體方法method1
        count++;    // 通路靜态變量count并指派
        System.out.println("在靜态方法 method1()中的 count="+count);    // 列印count
        return count;
    }
    public static int method2() {    
        // 靜态方法method2
        count += count;    // 通路靜态變量count并指派
        System.out.println("在靜态方法 method2()中的 count="+count);    // 列印count
        return count;
    }
    public static void PrintCount() {    
        // 靜态方法PrintCount
        count += 2;
        System.out.println("在靜态方法 PrintCount()中的 count="+count);    // 列印count
    }
    public static void main(String[] args) {
        StaticMethod sft = new StaticMethod();
        // 通過執行個體對象調用執行個體方法
        System.out.println("method1() 方法傳回值 intro1="+sft.method1());
        // 直接調用靜态方法
        System.out.println("method2() 方法傳回值 intro1="+method2());
        // 通過類名調用靜态方法,列印 count
        StaticMethod.PrintCount();
    }
}
           

(3) 靜态代碼塊

  • 靜态代碼塊指 Java 類中的 static{ } 代碼塊,主要用于初始化類,為類的靜态變量賦初始值
  • 靜态代碼可類似于一個方法,可以位于類中的任意位置,一個類中也可以有多個靜态代碼塊
  • java虛拟機在加載類時按其出現的順序執行一次靜态代碼塊
  • 靜态代碼塊中不能通路類的執行個體變量和執行個體方法,而需要類的執行個體對象來通路
public class StaticCode {
    public static int count = 0;
    
    // 非靜态代碼塊
    {
        count++;
        System.out.println("非靜态代碼塊 count=" + count);
    }
    
    static {
        count++;
        System.out.println("靜态代碼塊1 count=" + count);
    }
    
    static {
        count++;
        System.out.println("靜态代碼塊2 count=" + count);
    }

    public static void main(String[] args) {
        System.out.println("*************** StaticCode1 執行 ***************");
        StaticCode sct1 = new StaticCode();
        System.out.println("*************** StaticCode2 執行 ***************");
        StaticCode sct2 = new StaticCode();
    }
}
           

上述代碼中 { } 代碼塊為非靜态代碼塊,非靜态代碼塊是在建立對象時自動執行的代碼,不建立對象不執行該類的非靜态代碼塊。代碼域中定義的變量都是局部的,隻有域中的代碼可以調用。

2. final關鍵字

final表示對象是最終形态的,不可改變的。可用作變量、方法和類。

(1) 修飾變量

  • final修飾的變量即常量,其值不可改變(差別與不能指派)
  • final修飾的成員變量如果沒有指派時,需要在構造方法或者靜态代碼塊中初始化
  • final修飾的局部變量必須在使用前被指派一次
  • 對基本類型變量來說是其值不可變,而對對象引用類型變量來說其引用不可再變
  • 使用 final 修飾的引用類型變量不能被重新指派,但可以改變引用類型變量所引用對象的内容
  • 在使用 final 聲明變量時,要求全部的字母大寫
public class FinalDemo {
    void doSomething() {
        // 沒有在聲明的同時指派
        final int e;
        // 隻能指派一次
        e = 100;
        System.out.print(e);
        // 聲明的同時指派
        final int f = 200;
    }

    // 執行個體常量
    final int a = 5; // 直接指派
    final int b; // 空白final變量
    // 靜态常量
    final static int c = 12;// 直接指派
    final static int d; // 空白final變量
    // 靜态代碼塊
    static {
        // 初始化靜态變量
        d = 32;
    }

    // 構造方法
    FinalDemo() {
        // 初始化執行個體變量
        b = 3;
        // 第二次指派,會發生編譯錯誤
        // b = 4;
    }
}
           

(2) 修飾方法

final 修飾的方法不可被重寫,但可重載,若不希望子類重寫父類的某個方法,則可以使用 final 修飾該方法。

public class FinalMethodTest {

    public final void test() {
    }
}

class Sub extends FinalMethodTest {

    // 下面方法定義将出現編譯錯誤,不能重寫final方法
    public void test() {
    }
}
           

(3) 修飾類

final 修飾的類不能被繼承。

final class SuperClass {
}

class SubClass extends SuperClass {    //編譯錯誤
}
           

3. abstract關鍵字

  • java中有兩種類,一種是具體類,另一個種是抽象類
  • 用abstract修飾的類叫做抽象類,用abstract修飾的方法叫做抽象方法,抽象方法隻有方法的聲明,沒有方法的實作
  • abstract不能用于修飾靜态方法和構造方法
  • 抽象方法無方法體,必須存在于抽象類中,子類重寫父類時,必須重寫父類所有的抽象方法。
  • 在使用 abstract 關鍵字修飾抽象方法時不能使用 private 修飾,因為抽象方法必須被子類重寫,而如果使用了 private 聲明,則子類是無法重寫的
  • 抽象類中也可以有具體方法,抽象類不能執行個體化,即不能用new關鍵字建立對象

圖形的抽象類:

public abstract class Shape {
    public int width; // 幾何圖形的長
    public int height; // 幾何圖形的寬

    public Shape(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public abstract double area(); // 定義抽象方法,計算面積
}
           

正方形類:

public class Square extends Shape {
    public Square(int width, int height) {
        super(width, height);
    }

    // 重寫父類中的抽象方法,實作計算正方形面積的功能
    @Override
    public double area() {
        return width * height;
    }
}