天天看點

java final關鍵字_Java 常見關鍵字總結:final、static、this、super!

final,static,this,super 關鍵字總結

final 關鍵字

final關鍵字,意思是最終的、不可修改的,最見不得變化 ,用來修飾類、方法和變量,具有以下特點:
  1. final修飾的類不能被繼承,final類中的所有成員方法都會被隐式的指定為final方法;
  2. final修飾的方法不能被重寫;
  3. final修飾的變量是常量,如果是基本資料類型的變量,則其數值一旦在初始化之後便不能更改;如果是引用類型的變量,則在對其初始化之後便不能讓其指向另一個對象。

說明:使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實作版本中,會将final方法轉為内嵌調用。但是如果方法過于龐大,可能看不到内嵌調用帶來的任何性能提升(現在的Java版本已經不需要使用final方法進行這些優化了)。類中所有的private方法都隐式地指定為final。

static 關鍵字

static 關鍵字主要有以下四種使用場景:
  1. 修飾成員變量和成員方法: 被 static 修飾的成員屬于類,不屬于單個這個類的某個對象,被類中所有對象共享,可以并且建議通過類名調用。被static 聲明的成員變量屬于靜态成員變量,靜态變量 存放在 Java 記憶體區域的方法區。調用格式:

    類名.靜态變量名

    類名.靜态方法名()

  2. 靜态代碼塊: 靜态代碼塊定義在類中方法外, 靜态代碼塊在非靜态代碼塊之前執行(靜态代碼塊—>非靜态代碼塊—>構造方法)。 該類不管建立多少對象,靜态代碼塊隻執行一次.
  3. 靜态内部類(static修飾類的話隻能修飾内部類): 靜态内部類與非靜态内部類之間存在一個最大的差別: 非靜态内部類在編譯完成之後會隐含地儲存着一個引用,該引用是指向建立它的外圍類,但是靜态内部類卻沒有。沒有這個引用就意味着:1. 它的建立是不需要依賴外圍類的建立。2. 它不能使用任何外圍類的非static成員變量和方法。
  4. 靜态導包(用來導入類中的靜态資源,1.5之後的新特性): 格式為:

    import static

    這兩個關鍵字連用可以指定導入某個類中的指定靜态資源,并且不需要使用類名調用類中靜态成員,可以直接使用類中靜态成員變量和成員方法。

this 關鍵字

this關鍵字用于引用類的目前執行個體。 例如:

class Manager {
    Employees[] employees;
     
    void manageEmployees() {
        int totalEmp = this.employees.length;
        System.out.println("Total employees: " + totalEmp);
        this.report();
    }
     
    void report() { }
}
           

在上面的示例中,this關鍵字用于兩個地方:

  • this.employees.length:通路類Manager的目前執行個體的變量。
  • this.report():調用類Manager的目前執行個體的方法。

此關鍵字是可選的,這意味着如果上面的示例在不使用此關鍵字的情況下表現相同。 但是,使用此關鍵字可能會使代碼更易讀或易懂。

super 關鍵字

super關鍵字用于從子類通路父類的變量和方法。 例如:

public class Super {
    protected int number;
     
    protected showNumber() {
        System.out.println("number = " + number);
    }
}
 
public class Sub extends Super {
    void bar() {
        super.number = 10;
        super.showNumber();
    }
}
           

在上面的例子中,Sub 類通路父類成員變量 number 并調用其其父類 Super 的

showNumber()

方法。

使用 this 和 super 要注意的問題:
  • 在構造器中使用

    super()

    調用父類中的其他構造方法時,該語句必須處于構造器的首行,否則編譯器會報錯。另外,this 調用本類中的其他構造方法時,也要放在首行。
  • this、super不能用在static方法中。
簡單解釋一下:

被 static 修飾的成員屬于類,不屬于單個這個類的某個對象,被類中所有對象共享。而 this 代表對本類對象的引用,指向本類對象;而 super 代表對父類對象的引用,指向父類對象;是以,

this和super是屬于對象範疇的東西,而靜态方法是屬于類範疇的東西

static 關鍵字詳解

static 關鍵字主要有以下四種使用場景

  1. 修飾成員變量和成員方法
  2. 靜态代碼塊
  3. 修飾類(隻能修飾内部類)
  4. 靜态導包(用來導入類中的靜态資源,1.5之後的新特性)

修飾成員變量和成員方法(常用)

被 static 修飾的成員屬于類,不屬于單個這個類的某個對象,被類中所有對象共享,可以并且建議通過類名調用。被static 聲明的成員變量屬于靜态成員變量,靜态變量 存放在 Java 記憶體區域的方法區。

方法區與 Java 堆一樣,是各個線程共享的記憶體區域,它用于存儲已被虛拟機加載的類資訊、常量、靜态變量、即時編譯器編譯後的代碼等資料。雖然Java虛拟機規範把方法區描述為堆的一個邏輯部分,但是它卻有一個别名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。

HotSpot 虛拟機中方法區也常被稱為 “永久代”,本質上兩者并不等價。僅僅是因為 HotSpot 虛拟機設計團隊用永久代來實作方法區而已,這樣 HotSpot 虛拟機的垃圾收集器就可以像管理 Java 堆一樣管理這部分記憶體了。但是這并不是一個好主意,因為這樣更容易遇到記憶體溢出問題。

調用格式:

  • 類名.靜态變量名

  • 類名.靜态方法名()

如果變量或者方法被 private 則代表該屬性或者該方法隻能在類的内部被通路而不能在類的外部被通路。

測試方法:

public class StaticBean {

    String name;
    //靜态變量
    static int age;

    public StaticBean(String name) {
        this.name = name;
    }
    //靜态方法
    static void sayHello() {
        System.out.println("Hello i am java");
    }
    @Override
    public String toString() {
        return "StaticBean{"+
                "name=" + name + ",age=" + age +
                "}";
    }
}
public class StaticDemo {

    public static void main(String[] args) {
        StaticBean staticBean = new StaticBean("1");
        StaticBean staticBean2 = new StaticBean("2");
        StaticBean staticBean3 = new StaticBean("3");
        StaticBean staticBean4 = new StaticBean("4");
        StaticBean.age = 33;
        System.out.println(staticBean + " " + staticBean2 + " " + staticBean3 + " " + staticBean4);
        //StaticBean{name=1,age=33} StaticBean{name=2,age=33} StaticBean{name=3,age=33} StaticBean{name=4,age=33}
        StaticBean.sayHello();//Hello i am java
    }

}
           

靜态代碼塊

靜态代碼塊定義在類中方法外, 靜态代碼塊在非靜态代碼塊之前執行(靜态代碼塊 —> 非靜态代碼塊 —> 構造方法)。 該類不管建立多少對象,靜态代碼塊隻執行一次.

靜态代碼塊的格式是

static {    
    語句體;   
}
           

一個類中的靜态代碼塊可以有多個,位置可以随便放,它不在任何的方法體内,JVM加載類時會執行這些靜态的代碼塊,如果靜态代碼塊有多個,JVM将按照它們在類中出現的先後順序依次執行它們,每個代碼塊隻會被執行一次。

java final關鍵字_Java 常見關鍵字總結:final、static、this、super!

靜态代碼塊對于定義在它之後的靜态變量,可以指派,但是不能通路.

靜态内部類

靜态内部類與非靜态内部類之間存在一個最大的差別,我們知道非靜态内部類在編譯完成之後會隐含地儲存着一個引用,該引用是指向建立它的外圍類,但是靜态内部類卻沒有。沒有這個引用就意味着:

  1. 它的建立是不需要依賴外圍類的建立。
  2. 它不能使用任何外圍類的非static成員變量和方法。

Example(靜态内部類實作單例模式)

public class Singleton {
    
    //聲明為 private 避免調用預設構造方法建立對象
    private Singleton() {
    }
    
   // 聲明為 private 表明靜态内部該類隻能在該 Singleton 類中被通路
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
}
           

當 Singleton 類加載時,靜态内部類 SingletonHolder 沒有被加載進記憶體。隻有當調用

getUniqueInstance()

方法進而觸發

SingletonHolder.INSTANCE

時 SingletonHolder 才會被加載,此時初始化 INSTANCE 執行個體,并且 JVM 能確定 INSTANCE 隻被執行個體化一次。

這種方式不僅具有延遲初始化的好處,而且由 JVM 提供了對線程安全的支援。

靜态導包

格式為:import static

這兩個關鍵字連用可以指定導入某個類中的指定靜态資源,并且不需要使用類名調用類中靜态成員,可以直接使用類中靜态成員變量和成員方法

//将Math中的所有靜态資源導入,這時候可以直接使用裡面的靜态方法,而不用通過類名進行調用
 //如果隻想導入單一某個靜态方法,隻需要将換成對應的方法名即可
 
import static java.lang.Math.*;//換成import static java.lang.Math.max;具有一樣的效果
 
public class Demo {
  public static void main(String[] args) {
 
    int max = max(1,2);
    System.out.println(max);
  }
}
           

補充内容

靜态方法與非靜态方法

靜态方法屬于類本身,非靜态方法屬于從該類生成的每個對象。 如果您的方法執行的操作不依賴于其類的各個變量和方法,請将其設定為靜态(這将使程式的占用空間更小)。 否則,它應該是非靜态的。

Example

class Foo {
    int i;
    public Foo(int i) { 
       this.i = i;
    }

    public static String method1() {
       return "An example string that doesn't depend on i (an instance variable)";
       
    }

    public int method2() {
       return this.i + 1;  //Depends on i
    }

}
           

你可以像這樣調用靜态方法:

Foo.method1()

。 如果您嘗試使用這種方法調用 method2 将失敗。 但這樣可行

Foo bar = new Foo(1);
bar.method2();
           

總結:

  • 在外部調用靜态方法時,可以使用”類名.方法名”的方式,也可以使用”對象名.方法名”的方式。而執行個體方法隻有後面這種方式。也就是說,調用靜态方法可以無需建立對象。
  • 靜态方法在通路本類的成員時,隻允許通路靜态成員(即靜态成員變量和靜态方法),而不允許通路執行個體成員變量和執行個體方法;執行個體方法則無此限制

static{}

靜态代碼塊與

{}

非靜态代碼塊(構造代碼塊)

相同點: 都是在JVM加載類時且在構造方法執行之前執行,在類中都可以定義多個,定義多個時按定義的順序執行,一般在代碼塊中對一些static變量進行指派。

不同點: 靜态代碼塊在非靜态代碼塊之前執行(靜态代碼塊 -> 非靜态代碼塊 -> 構造方法)。靜态代碼塊隻在第一次new執行一次,之後不再執行,而非靜态代碼塊在每new一次就執行一次。 非靜态代碼塊可在普通方法中定義(不過作用不大);而靜态代碼塊不行。

修正 issue #677:靜态代碼塊可能在第一次new的時候執行,但不一定隻在第一次new的時候執行。比如通過

Class.forName("ClassDemo")

建立 Class 對象的時候也會執行。

一般情況下,如果有些代碼比如一些項目最常用的變量或對象必須在項目啟動的時候就執行的時候,需要使用靜态代碼塊,這種代碼是主動執行的。如果我們想要設計不需要建立對象就可以調用類中的方法,例如:Arrays類,Character類,String類等,就需要使用靜态方法, 兩者的差別是 靜态代碼塊是自動執行的而靜态方法是被調用的時候才執行的.

Example:

public class Test {
    public Test() {
        System.out.print("預設構造方法!--");
    }

    //非靜态代碼塊
    {
        System.out.print("非靜态代碼塊!--");
    }

    //靜态代碼塊
    static {
        System.out.print("靜态代碼塊!--");
    }

    private static void test() {
        System.out.print("靜态方法中的内容! --");
        {
            System.out.print("靜态方法中的代碼塊!--");
        }

    }

    public static void main(String[] args) {
        Test test = new Test();
        Test.test();//靜态代碼塊!--靜态方法中的内容! --靜态方法中的代碼塊!--
    }
}
           

上述代碼輸出:

靜态代碼塊!--非靜态代碼塊!--預設構造方法!--靜态方法中的内容! --靜态方法中的代碼塊!--
           

當隻執行

Test.test();

時輸出:

靜态代碼塊!--靜态方法中的内容! --靜态方法中的代碼塊!--
           

當隻執行

Test test = new Test();

時輸出:

靜态代碼塊!--非靜态代碼塊!--預設構造方法!--
           

非靜态代碼塊與構造函數的差別是: 非靜态代碼塊是給所有對象進行統一初始化,而構造函數是給對應的對象初始化,因為構造函數是可以多個的,運作哪個構造函數就會建立什麼樣的對象,但無論建立哪個對象,都會先執行相同的構造代碼塊。也就是說,構造代碼塊中定義的是不同對象共性的初始化内容。

作者:Snailclimb

連結:Java 常見關鍵字總結:final、static、this、super!

來源:github

繼續閱讀