1. 程式人生 > 其它 >Java中的static關鍵字解析

Java中的static關鍵字解析

在Java語言中,static表示“靜態”的意思,使用場景可以用來修飾成員變數和成員方法,當然也可以是靜態程式碼塊。static的主要作用在於建立獨立於具體物件的域變數或者方法。本文主要來去講解一下static的來龍去脈。

static格式:

  • 修飾變數:static 資料型別 變數名
  • 修飾方法:【訪問許可權修飾符】 static 方法返回值 方法名(引數列表)

static的特點:

  • static可以修飾成員變數也可以修飾成員方法
  • 靜態資源隨著類的載入而載入
  • 被static修飾的變數或者方法是優先於物件存在的,也就是說當一個類載入完畢之後,即便沒有建立物件,也可以去訪問。
  • 被static修飾的變數或者方法是獨立於該類的任何物件,也就是說,這些變數和方法不屬於任何一個例項物件,而是被類的例項物件所共享。

static方法:

static方法一般稱作靜態方法;

靜態方法可以不依附於任何物件,因此他不需要建立物件便可呼叫,呼叫格式:類名.靜態方法名();

重點: 靜態中沒有super和this關鍵字

因為this和super只有建立物件之後才存在,靜態則是隨著類的載入而載入,在使用靜態的時候,有可能物件還沒有被建立

static變數:

static變數也稱作靜態變數;

靜態變數和非靜態變數的區別是:靜態變數被所有的物件所共享,在記憶體中只有一個副本,它當且僅當在類初次載入時會被初始化。而非靜態變數是物件所擁有的,在建立物件的時候被初始化,存在多個副本,各個物件擁有的副本互不影響。

static成員變數的初始化順序按照定義的順序進行初始化。

static程式碼塊:

static關鍵字還有一個比較關鍵的作用就是 用來形成靜態程式碼塊以優化程式效能。static塊可以置於類中的任何地方,類中可以有多個static塊。在類初次被載入的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次。

class Person{
    private Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

isBornBoomer是用來這個人是否是1946-1964年出生的,而每次isBornBoomer被呼叫的時候,都會生成startDate和birthDate兩個物件,造成了空間浪費,如果改成這樣效率會更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }
     
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

static注意事項:

1、在靜態方法中沒有this關鍵字因為靜態是隨著類的載入而載入,而this是隨著物件的建立而存在的。靜態比物件優先存在。
2、靜態可以訪問靜態的,但是靜態不能訪問非靜態的。
3、非靜態的可以去訪問靜態的。

static關鍵字的誤區:

與C/C++中的static不同,Java中的static關鍵字不會影響到變數或者方法的作用域。在Java中能夠影響到訪問許可權的只有private、public、protected(包括包訪問許可權)這幾個關鍵字。

常見的筆試面試題:

1.下面這段程式碼的輸出結果是什麼?

public class Test extends Base{
 
    static{
        System.out.println("test static");
    }
     
    public Test(){
        System.out.println("test constructor");
    }
     
    public static void main(String[] args) {
        new Test();
    }
}
 
class Base{
     
    static{
        System.out.println("base static");
    }
     
    public Base(){
        System.out.println("base constructor");
    }
}
點選檢視程式碼
base static
test static
base constructor
test constructor
至於為什麼是這個結果,我們先不討論,先來想一下這段程式碼具體的執行過程,在執行開始,先要尋找到main方法,因為main方法是程式的入口,但是在執行main方法之前,必須先載入Test類,而在載入Test類的時候發現Test類繼承自Base類,因此會轉去先載入Base類,在載入Base類的時候,發現有static塊,便執行了static塊。在Base類載入完成之後,便繼續載入Test類,然後發現Test類中也有static塊,便執行static塊。在載入完所需的類之後,便開始執行main方法。在main方法中執行new Test()的時候會先呼叫父類的構造器,然後再呼叫自身的構造器。因此,便出現了上面的輸出結果。

2.這段程式碼的輸出結果是什麼?

public class Test {
    Person person = new Person("Test");
    static{
        System.out.println("test static");
    }
     
    public Test() {
        System.out.println("test constructor");
    }
     
    public static void main(String[] args) {
        new MyClass();
    }
}
 
class Person{
    static{
        System.out.println("person static");
    }
    public Person(String str) {
        System.out.println("person "+str);
    }
}
 
 
class MyClass extends Test {
    Person person = new Person("MyClass");
    static{
        System.out.println("myclass static");
    }
     
    public MyClass() {
        System.out.println("myclass constructor");
    }
}
點選檢視程式碼
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

類似地,我們還是來想一下這段程式碼的具體執行過程。首先載入Test類,因此會執行Test類中的static塊。接著執行new MyClass(),而MyClass類還沒有被載入,因此需要載入MyClass類。在載入MyClass類的時候,發現MyClass類繼承自Test類,但是由於Test類已經被載入了,所以只需要載入MyClass類,那麼就會執行MyClass類的中的static塊。在載入完之後,就通過構造器來生成物件。而在生成物件的時候,必須先初始化父類的成員變數,因此會執行Test中的Person person = new Person(),而Person類還沒有被載入過,因此會先載入Person類並執行Person類中的static塊,接著執行父類的構造器,完成了父類的初始化,然後就來初始化自身了,因此會接著執行MyClass中的Person person = new Person(),最後執行MyClass的構造器。

3.這段程式碼的輸出結果是什麼?

public class Test {
     
    static{
        System.out.println("test static 1");
    }
    public static void main(String[] args) {
         
    }
     
    static{
        System.out.println("test static 2");
    }
}
點選檢視程式碼
test static 1
test static 2

雖然在main方法中沒有任何語句,但是還是會輸出,原因上面已經講述過了。另外,static塊可以出現類中的任何地方(只要不是方法內部,記住,任何方法內部都不行),並且執行是按照static塊的順序執行的。

來源:來源地址