天天看點

【Java】static關鍵字

前言

static關鍵字算是Java中比較複雜的關鍵字之一,它可以修飾變量、方法、類以及代碼塊。下面将介紹static的具體使用。并且擴充介紹關于程式入口函數

public static void main(String[] args)

的一些知識。

引入static的目的

在《Java程式設計思想》中對static的描述有這樣的一句話:

static方法就是沒有this的方法。在static的方法内部不能調用非靜态方法,反過來到是可以的。而且可以在沒有建立任何對象的前提下,僅僅通過類本身來調用static方法。

這最後一句便是引入static主要的用途,免去建立類對象的開銷就可以調用類中的方法,可以說是十分誘人。

static的作用

Static修飾變量

private static int num;
           

變量num可以稱為靜态變量也可以稱為類變量。

static修飾屬性隻能修飾類屬性,不可以修飾局部變量,如方法中的定義的屬性。J

Java中的static和C++中的static含義是不一樣的,C++中的static修飾的變量是全局變量,而Java中沒有全局變量的概念,在Java中使用static修飾的類屬性是存放在

方法區

的,為該類所有對象共享的變量,與具體某個對象沒有關系。

static屬性和非static屬性的差別主要有兩點:

  1. 在記憶體區域的儲存位置不同,static屬性存放在方法區,非static屬性存放在堆棧區。
  2. static屬性是屬于類對象的公共屬性,可以在沒有執行個體化對象的前提下使用

    類名.靜态屬性名

    的方式通路;而非static屬性則需要使用對象進行通路。

關于什麼時候該使用static屬性?

需要進行描述共享資訊的屬性并且該屬性不需要重複開辟記憶體空間而且便于修改,則使用static進行修飾該變量。

static修飾方法

public static void printNumberOfStudent(){
  ...
}
           

被static修飾的方法叫做靜态方法。靜态方法同靜态變量一樣可以直接使用

類名稱.靜态方法名

調用。若是使用類名調用靜态方法需要滿足該方法不是private。在非靜态方法中是可以使用this通路靜态變量。

在使用靜态方法時需要注意兩點:

  • 靜态方法中是不存在this的。因為this是指向目前對象的,靜态方法是與類相關的,與對象無關,不存在對象調用問題。一般直接使用

    類名.靜态方法名

    進行通路
  • 靜态方法内部隻能直接調用靜态方法和靜态成員。調用普通方法會報錯,在普通方法中可以調用靜态方法。

    因為普通方法一般會将對象作為隐藏實參傳入并用this指向,在沒有建立對象時,普通方法中就不存在this,調用包含普通方法的靜态方法就會報錯!

static修飾代碼塊

在程式編寫中可以直接使用

{...}

定義一段語句塊,這個語句塊就是代碼塊,使用static修飾的語句塊就叫做靜态代碼塊。

觀察下面程式的結果,分析靜态塊在程式中的執行順序

public class A {
    A(){
        System.out.println("A constructor");
    }
    static {
        System.out.println("A's static block");
    }
}
public class B extends A{
    B(){
        System.out.println("B constructor");
    }
    static {
        System.out.println("B's static block");
    }
}

public class StaticBlock {
    public static void main(String[] args) {
        B objb = new B();
    }
}

/*output
A's static block
B's static block
A constructor
B constructor
*/
           

可以看出

靜态代碼塊的執行順序優先于構造函數

,在程式執行時,會先找到main入口,然後準備加載類B,發現B有父類A,于是先去加載A,靜态代碼塊就是在類加載的時候執行的。在靜态塊執行完後,就會去執行構造函數。

靜态塊因為在構造函數之前執行,是以

常用來初始化靜态變量

public  class Student {
    private static int numOfStu;
    private String name;
    private int age;

    static {
        numOfStu = 0;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        numOfStu++;
    }
}
           
靜态代碼塊可以在類的任意位置定義

(方法中不可以),不會影響其優先于構造函數執行的順序。但是多個靜态塊的執行順序會依據其聲明的前後執行。

public  class Student {
    private static int numOfStu;
    private String name;
    private int age;

    static {
        numOfStu = 0;
        System.out.println("first sttaic block");
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        numOfStu++;
    }

    static {
        System.out.println("second sttaic block");
    }

    public static void main(String[] args) {
        Student stu1 = new Student("sakura",20);
    }
}
/*
output:
first sttaic block
second sttaic block
*/
           

static修飾内部類

内部類顧名思義就是定義在一個類中的類。使用static定義的屬性或者方法是不受類執行個體化對象的控制的,是以,如果内部類被static修飾,是不會受到外部類執行個體化對象控制。此時,

内部類就相等于變成了一個外部類,并且隻能通路外部類中的static屬性或者方法

。關于内部類,後面會詳細介紹。

public static void main(String[] args)

class Test{
  ...
  public static void main(String[] args){
  ...
  }
}
           

public static void main(String[] args)

作為Java程式的入口方法,Java虛拟機在運作程式時,會首先查找main()方法。該方法中各個修飾符的作用如下:

  • 【public】: public 作為權限修飾符,表明任何類或者對象都可以通路這個方法。主方法是程式的開始,是以這個方法對任何操作都應該是可見。
  • 【static】: static表明main()方法是一個靜态方法,即方法中的代碼是存儲在靜态存儲區的,當類被加載後,就可以直接使用類名來調用(在指令行使用

    java Test

    是調用Test.main主方法)。如此看被static修飾的主函數,這樣的好處可能就是:不用建立目前類的對象就可以調用,節省空間。
  • 【void】: 主方法是一切執行的開始點,既然是起點,那麼就沒有回到其他方法中的傳回值
  • 【String[] args】: 傳遞給程式的參數。輸入的參數以空格隔開,若是輸入的參數本省有空格,則使用雙引号将該參數括起來。字元串參數args為開發人員在指令行狀态下與程式互動提供了一種手段。

擴充一: main()方法是否還有其他可用的定義格式?

  1. 由于public和static沒有先後順序關系,是以下面的定義也是合理的
    static public void main(String[] args)
               
  2. 也可以将main()方法定義為final的
    public static  final void main(String[] args)
               
  3. 也可以使用synchronized關鍵字來修飾
    static public synchronized void main(String[] args)
               

但是不管使用哪種方式定義,都需要保證main()方法的傳回值為void,并且有static和public關鍵字修飾。因為main()方法作為程式的入口,是以不能使用abstract關鍵字來修飾!

擴充二: 同一個.java檔案中是否可以有多個main()方法?

雖然每個類中都可以定義main()方法,但是隻有與檔案名相同的用public修飾的類中的main()方法才能作為整個程式的入口方法。如下所示:建立一個名為Test.java的檔案

class T{
    public static void main(String[] args){
        System.out.println("T main");
    }
}
public class Test{
    // 程式入口函數
    public static void main(String[] args){
        System.out.println("Test main");
    }
}
/*
output:
Test main
*/
           

小結

介紹了Java中static關鍵字的基礎應用:修飾變量、方法等。Java中還可以利用static關鍵字實作

單例模式

,這些後面介紹。

參考:

[1] Eckel B. Java程式設計思想(第四版)[M]. 北京: 機械工業出版社, 2007

每天進步一點點,不要停止前進的腳步~