天天看點

java-基礎-static

“static方法就是沒有this的方法。在static方法内部不能調用非靜态方法,反過來是可以的。而且可以在沒有建立任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途。”

這段話雖然隻是說明了static方法的特殊之處,但是可以看出static關鍵字的基本作用,簡而言之,一句話來描述就是:

  友善在沒有建立對象的情況下來進行調用(方法/變量)。

  很顯然,被static關鍵字修飾的方法或者變量不需要依賴于對象來進行通路,隻要類被加載了,就可以通過類名去進行通路。

static可以用來修飾類的成員方法、類的成員變量,另外可以編寫static代碼塊來優化程式性能。

static方法

static方法一般稱作靜态方法,由于靜态方法不依賴于任何對象就可以進行通路,是以對于靜态方法來說,是沒有this的,因為它不依附于任何對象,既然都沒有對象,就談不上this了。并且由于這個特性,在靜态方法中不能通路類的非靜态成員變量和非靜态成員方法,因為非靜态成員方法/變量都是必須依賴具體的對象才能夠被調用。

但是要注意的是,雖然在靜态方法中不能通路非靜态成員方法和非靜态成員變量,但是在非靜态成員方法中是可以通路靜态成員方法/變量的。由于你無法預知在print1方法中是否通路了非靜态成員變量,是以也禁止在靜态成員方法中通路非靜态成員方法。

而對于非靜态成員方法,它通路靜态成員方法/變量顯然是毫無限制的。

是以,如果說想在不建立對象的情況下調用某個方法,就可以将這個方法設定為static。我們最常見的static方法就是main方法,至于為什麼main方法必須是static的,現在就很清楚了。因為程式在執行main方法的時候沒有建立任何對象,是以隻有通過類名來通路。

另外記住,即使沒有顯示地聲明為static,類的構造器實際上也是靜态方法。

 static變量也稱作靜态變量,靜态變量和非靜态變量的差別是:靜态變量被所有的對象所共享,在記憶體中隻有一個副本,它當且僅當在類初次加載時會被初始化。而非靜态變量是對象所擁有的,在建立對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。

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

static代碼塊

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

  為什麼說static塊可以用來優化程式性能,是因為它的特性:隻會在類加載的時候執行一次。下面看個例子:

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

是以,很多時候會将一些隻需要進行一次的初始化操作都放在static代碼塊中進行。

1.static關鍵字會改變類中成員的通路權限嗎?

  有些初學的朋友會将java中的static與C/C++中的static關鍵字的功能混淆了。在這裡隻需要記住一點:與C/C++中的static不同,Java中的static關鍵字不會影響到變量或者方法的作用域。在Java中能夠影響到通路權限的隻有private、public、protected(包括包通路權限)這幾個關鍵字。static關鍵字并不會改變變量和方法的通路權限。

2、能通過this通路靜态成員變量嗎?

雖然對于靜态方法來說沒有this,那麼在非靜态方法中能夠通過this通路靜态成員變量嗎?

這裡面主要考察隊this和static的了解。this代表什麼?this代表目前對象,那麼通過new Main()來調用printValue的話,目前對象就是通過new Main()生成的對象。而static變量是被對象所享有的,是以在printValue中的this.value的值毫無疑問是33。在printValue方法内部的value是局部變量,根本不可能與this關聯,是以輸出結果是33。在這裡永遠要記住一點:靜态成員變量雖然獨立于對象,但是不代表不可以通過對象去通路,所有的靜态方法和靜态變量都可以通過對象通路(隻要通路權限足夠)。

3、3.static能作用于局部變量麼?

  在C/C++中static是可以作用域局部變量的,但是在Java中切記:static是不允許用來修飾局部變量。

至于為什麼是這個結果,我們先不讨論,先來想一下這段代碼具體的執行過程,在執行開始,先要尋找到main方法,因為main方法是程式的入口,但是在執行main方法之前,必須先加載Test類,而在加載Test類的時候發現Test類繼承自Base類,是以會轉去先加載Base類,在加載Base類的時候,發現有static塊,便執行了static塊。在Base類加載完成之後,便繼續加載Test類,然後發現Test類中也有static塊,便執行static塊。在加載完所需的類之後,便開始執行main方法。在main方法中執行new Test()的時候會先調用父類的構造器,然後再調用自身的構造器。是以,便出現了上面的輸出結果。

類似地,我們還是來想一下這段代碼的具體執行過程。首先加載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的構造器。

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