Java中的static關(guān)鍵字解析

static關(guān)鍵字的用途

方便在沒有創(chuàng)建對象的情況下來進(jìn)行調(diào)用(方法/變量)。
被static關(guān)鍵字修飾的方法或者變量不需要依賴于對象來進(jìn)行訪問,只要類被加載了,就可以通過類名去進(jìn)行訪問。
static可以用來修飾類的成員方法類的成員變量、內(nèi)部類,另外可以編寫static代碼塊來優(yōu)化程序性能。
static定義的資源(變量、靜態(tài)代碼塊)的初始化順序按照定義的順序進(jìn)行初始化。

static關(guān)鍵字的用法

(1)static靜態(tài)變量

被static修飾的變量屬于類變量,可以通過類名.變量名直接引用,而不需要new出一個對象來.static成員變量的初始化順序按照定義的順序進(jìn)行初始化。

靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對象所共享,在內(nèi)存中只有一份,它當(dāng)且僅當(dāng)在類初次加載時會被初始化。而非靜態(tài)變量是對象所擁有的,在創(chuàng)建對象的時候被初始化,各個對象擁有各自的變量互不影響。
另外記?。?strong>static是不允許用來修飾局部變量。比如


上面會報錯的,這是一個java的規(guī)范。

(2)static靜態(tài)方法

被static修飾的方法屬于類方法,可以通過類名.方法名直接引用,而不需要new出一個對象來,被static修飾的變量、被static修飾的方法統(tǒng)一屬于類的靜態(tài)資源,是類實例之間共享的,換言之,一處變、處處變。

在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法/變量的。舉個簡單的例子:


在上面的代碼中,由于print2方法是獨立于對象存在的,可以直接用過類名調(diào)用。假如說可以在靜態(tài)方法中訪問非靜態(tài)方法/變量的話,那么如果在main方法中有下面一條語句:
MyObject.print2();
此時對象都沒有,str2根本就不存在,所以就會產(chǎn)生矛盾了。同樣對于方法也是一樣,由于你無法預(yù)知在print1方法中是否訪問了非靜態(tài)成員變量,所以也禁止在靜態(tài)成員方法中訪問非靜態(tài)成員方法。而對于非靜態(tài)成員方法,它訪問靜態(tài)成員方法/變量顯然是毫無限制的。

這里總結(jié)一下靜態(tài)和非靜態(tài)之間的引用:
1、靜態(tài)方法能不能引用非靜態(tài)資源?不能,new的時候才會產(chǎn)生的東西,對于初始化后就存在的靜態(tài)資源來說,根本不認(rèn)識它。
2、靜態(tài)方法里面能不能引用靜態(tài)資源?可以,因為都是類初始化的時候加載的,大家相互都認(rèn)識。
3、非靜態(tài)方法里面能不能引用靜態(tài)資源?可以,非靜態(tài)方法就是實例方法,那是new之后才產(chǎn)生的,那么屬于類的內(nèi)容它都認(rèn)識。

(3)static靜態(tài)代碼塊

static關(guān)鍵字還有一個比較關(guān)鍵的作用就是 用來形成靜態(tài)代碼塊以優(yōu)化程序性能。static塊可以置于類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執(zhí)行每個static塊,并且只會執(zhí)行一次。
為什么說static塊可以用來優(yōu)化程序性能,是因為它的特性:只會在類加載的時候執(zhí)行一次

(4)static靜態(tài)內(nèi)部類

static一般情況下來說是不可以修飾類的,如果static要修飾一個類,說明這個類是一個靜態(tài)內(nèi)部類(注意static只能修飾一個內(nèi)部類)

static關(guān)鍵字的誤區(qū)

  • (1) 能通過this訪問靜態(tài)成員變量嗎?
    雖然對于靜態(tài)方法來說沒有this,那么在非靜態(tài)方法中能夠通過this訪問靜態(tài)成員變量嗎?先看下面的一個例子,這段代碼輸出的結(jié)果是什么?
public class Main {  
    static int value = 33;
 
    public static void main(String[] args) throws Exception{
        new Main().printValue();
    }
 
    private void printValue(){
        int value = 3;
        System.out.println(this.value);
    }
}

輸出結(jié)果:

33

這里面主要考察隊this和static的理解。this代表什么?this代表當(dāng)前對象,那么通過new Main()來調(diào)用printValue的話,當(dāng)前對象就是通過new Main()生成的對象。而static變量是被對象所享有的,因此在printValue中的this.value的值毫無疑問是33。在printValue方法內(nèi)部的value是局部變量,根本不可能與this關(guān)聯(lián),所以輸出結(jié)果是33。在這里永遠(yuǎn)要記住一點:靜態(tài)成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問,所有的靜態(tài)方法和靜態(tài)變量都可以通過對象訪問(只要訪問權(quán)限足夠)。

  • (2) static能作用于局部變量么?

在C/C++中static是可以作用域局部變量的,但是在Java中切記:static是不允許用來修飾局部變量。不要問為什么,這是Java語法的規(guī)定。

常見的筆試面試題

1.下面這段代碼的輸出結(jié)果是什么?

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");
    }
}

輸出結(jié)果

base static
test static
base constructor
test constructor

至于為什么是這個結(jié)果,我們先不討論,先來想一下這段代碼具體的執(zhí)行過程,在執(zhí)行開始,先要尋找到main方法,因為main方法是程序的入口,但是在執(zhí)行main方法之前,必須先加載Test類,而在加載Test類的時候發(fā)現(xiàn)Test類繼承自Base類,因此會轉(zhuǎn)去先加載Base類,在加載Base類的時候,發(fā)現(xiàn)有static塊,便執(zhí)行了static塊。在Base類加載完成之后,便繼續(xù)加載Test類,然后發(fā)現(xiàn)Test類中也有static塊,便執(zhí)行static塊。在加載完所需的類之后,便開始執(zhí)行main方法。在main方法中執(zhí)行new Test()的時候會先調(diào)用父類的構(gòu)造器,然后再調(diào)用自身的構(gòu)造器。因此,便出現(xiàn)了上面的輸出結(jié)果。

2.這段代碼的輸出結(jié)果是什么?

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");
    }
}

輸出結(jié)果:

test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

類似地,我們還是來想一下這段代碼的具體執(zhí)行過程。首先加載Test類,因此會執(zhí)行Test類中的static塊。接著執(zhí)行new MyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。在加載MyClass類的時候,發(fā)現(xiàn)MyClass類繼承自Test類,但是由于Test類已經(jīng)被加載了,所以只需要加載MyClass類,那么就會執(zhí)行MyClass類的中的static塊。在加載完之后,就通過構(gòu)造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執(zhí)行Test中的Person person = new Person(),而Person類還沒有被加載過,因此會先加載Person類并執(zhí)行Person類中的static塊,接著執(zhí)行父類的構(gòu)造器,完成了父類的初始化,然后就來初始化自身了,因此會接著執(zhí)行MyClass中的Person person = new Person(),最后執(zhí)行MyClass的構(gòu)造器。

3.這段代碼的輸出結(jié)果是什么?

public class Test {
     
    static{
        System.out.println("test static 1");
    }
    public static void main(String[] args) {
         
    }
     
    static{
        System.out.println("test static 2");
    }
}

輸出結(jié)果:

test static 1
test static 2

static塊可以出現(xiàn)類中的任何地方(只要不是方法內(nèi)部,記住,任何方法內(nèi)部都不行),并且執(zhí)行是按照static塊的順序執(zhí)行的。

原博文:
Java中的static關(guān)鍵字解析
static關(guān)鍵字作用總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容