前言
static關鍵字是擺在剛入行編程語言的小白們面前的一道難題,為什麼要用static?使用它有什麼好處?修飾方法和修飾變量有什麼區別?本文將就java中static關鍵字的使用方法及注意事項進行深入探討,一是為了方便自己以後查閱,二也為了與大家交流分享學習的經驗。
一、什麼是static關鍵字
static表示靜態,常用來修飾成員變量、成員方法、代碼塊和內部類,存放在方法區,作用在於創建獨立於對象存在的域變量或方法,當類被加載時,被static修飾的變量或方法就可以通過類名進行訪問,當創建多個對象時,被static修飾的變量/方法不會因此建立多個數據。
我們通過下面一段代碼來解釋一下它的功能:
<code>public
class
Demo1
{public
static
void
main
(String[] args
) { Test.p="靜態變量賦值了"
; Test.say();new
Test(); } }class
Test
{ Test(){ System.out
.println("構造方法執行了"
); }static
String p ;static
{ System.out
.println("靜態代碼塊執行了"
); }public
static
void
say
(){ System.out
.println("靜態方法執行了"
); System.out
.println(p); }public
void
say2
(){ System.out
.println("方法執行了"
); System.out
.println(p); } } /<code>
代碼中我們分別使用關鍵字static定義了靜態變量、靜態代碼塊和靜態方法,執行結果如下
我們發現,最先執行的語句是static修飾的代碼塊,在我們通過類名直接調用方法say之前就執行了,隨後是我們通過類名訪問的靜態方法say,最後才是構造方法。到這裡小白可能會問,為什麼我們還沒有創建對象就可以訪問類中的內容呢?這就涉及到了關鍵字static的使用方法。
二、static關鍵字的使用方法
1.修飾變量和方法**
被static修飾的變量和方法我們統稱為靜態變量和靜態方法,屬於類的靜態資源,是類實例之間共享的,簡單地說,即不隨著創建對象的改變而發生改變。以普通變量和方法為例:我們寫一段簡單的代碼
<code>public
class
Demo1
{public
static
void
main
(String[] args
) { Test t1 =new
Test(); Test t2 =new
Test(); t1.p ="變量賦值了"
; t1.x =1
; t2.x =2
; t1.say(); } }class
Test
{ String p;static
int
x;void
say
(){ System.out
.println("方法執行了"
); System.out
.println(p); System.out
.println(x); } } /<code>
這段代碼很簡單,即我們通過創建的對象t來訪問Test類中的內容,與上一段代碼不同的是我們不能通過類名的方式來直接調用這些變量方法,如Test.p和Test.say,而是要通過創建的新對象t。但是我們卻可以用對象t來訪問靜態變量x,但是變量x的內容屬於類,對象t1,t2是共享一個變量x的,通過兩個對象賦值後,結果取最後賦的值,所以輸出的結果如下。
2.靜態代碼塊
靜態靜態塊也是static的重要應用之一。通常使用於類的初始化,和靜態變量、靜態方法一樣,靜態塊裡面的代碼只執行一次,且只在初始化類的時候執行。為了更清楚地描述靜態代碼塊的功能,我們編寫如下代碼。
<code>public
class
Demo1
{public
static
void
main
(String[] args
) {new
Test2();new
Test1(); } }class
Test2
extends
Test1
{static
{ System.out
.println("靜態代碼塊1執行了"
); }static
{ System.out
.println("靜態代碼塊2執行了"
); } }class
Test1
{static
{ System.out
.println("靜態代碼塊3執行了"
); } } /<code>
不難看出,靜態代碼塊隨著對象的創建,或者說類的實例化而進行,且只進行一次,我們創建了兩個對象,但是每個語句只打印了一次。我們根據他們打印的順序可以推斷出靜態代碼塊的執行規則。1.按照父類到子類的順序執行。2.在同一個類中按照代碼的順序執行3.每個靜態代碼塊只執行一次靜態代碼塊可以優化程序性能,正是因為它的特性:只會在類被初次加載的時候執行一次。
3.靜態內部類
static正常情況下是不能用來修飾類的,它只能修飾內部類,也就是我們說的靜態內部類,它的應用場景相對於以上兩個功能少得多,通常我們使用內部類時會保存一個引用,引用是指向創建它的外圍內,但是靜態內部類卻沒有。沒有這個引用就意味著:1、它的創建是不需要依賴外圍類的創建。2、它不能使用任何外圍類的非static成員變量和方法。我們通過代碼示例來簡單地介紹一下靜態內部類使用方法
<code> package com.java.demo1;public
class
Demo1
{public
static
void
main
(String[] args
) { Test.Test2 t =new
Test.Test2(); t.say(); } }class
Test
{static
class
Test2
{void
say
(){ System.out
.println("靜態內部類"
); } } } /<code>
三、為什麼要使用static
好了,說到這裡,可能一些初學者會問,為什麼要使用靜態呢?首先我們總結一下被靜態static修飾的變量/方法/方法塊/類的特點
靜態修飾的特點1.被static修飾的變量/方法是獨立與類所創建的對象而存在的,簡而言之,當我們創建多個對象實例時,static修飾的變量/方法是被它們所共享的,即不隨著不同對象的創建而發生改變。2.static在類加載時就創建好了內存空間,但是它的內容是可以改變的,我們可以通過不同的對象給它賦值,但是它的值取決於你最終給它的賦值。3.即便不創建對象,static修飾的變量或方法也是可以存在的,當一個類加載完畢後,類中static修飾的變量和方法就可以進行訪問。
靜態修飾的優點1.方便在我們沒有創建對象時,調用類中的方法/變量2.static可以用來修飾類的成員方法、成員變量或編寫static代碼塊,能夠有效地優化程序性能我們可以通過下面一段代碼來直觀地感受一下
<code>package com.java.demo1;public
class
Demo1
{public
static
void
main
(String[] args
) { Test t1 =new
Test(); Test t2 =new
Test(); Test t3 =new
Test(); t1.name ="張三"
; t2.name ="李四"
; t3.name ="王麻子"
; t1.age =18
; t2.age =18
; t3.age =19
; Test.school ="清華大學"
; t1.say(); t2.say(); t3.say(); } }class
Test
{ String name;int
age;static
String school;void
say
(){ System.out
.println("我是"
+name+",今年"
+age+"歲,就讀於"
+school); } } /<code>
運行結果如下
對於三個對象,他們的school屬性是完全相同的,因此為了不佔用過多內存,我們用static把變量school修飾成靜態變量,如果我們發現變量school的內容寫錯了,也可以通過一次修改就達成修改所有對象的目的。
四、注意事項
介紹完了static的優點,接下來說一些使用static關鍵字時經常出現的錯誤和需要大家注意的一些細節。
1.static不會改變類中成員的訪問權限
很多初學者容易把java中的static和C/C++中的static搞混了,在C/C++中,static能夠改變成員的訪問權限,而這在java中時不行的,在java中只能通過四個權限修飾符來改變成員的訪問權限
如圖所示,我們直接給private封裝的變量school賦值時,會提示錯誤。
2.靜態方法不能引用非靜態資源
這一點是初學者經常犯的錯誤,當我們定義了一個非靜態的變量/方法後,如果我們通過靜態的變量或方法來訪問非靜態的資源時程序是會報錯的。這其實不難理解,我們之前說過,靜態修飾的變量/方法在類初始化時加載,它們的創建順序是在非靜態資源之前的,我們用已經創建的資源去訪問沒有被創建的資源,這顯然是不合理的。但反過來,非靜態資源/靜態資源則是可以訪問靜態資源的。我們通過代碼來直觀地感受一下。
3.可以通過this來訪問靜態的資源
雖然我們之前提到過,靜態的資源本身是獨立於實例化的對象而存在的,但是我們卻可以通過對象來訪問靜態的資源,所有的靜態方法和靜態變量都可以通過對象訪問(只要訪問權限足夠)。我們再通過一個案例來感受:
<code>public
class
Demo1
{public
static
void
main
(String[] args
) { Test t =new
Test(); t.say(); } }class
Test
{static
int
num =1
;void
say
(){int
num =2
; System.out
.println(this
.num); } } /<code>
結果輸出為1,代碼中的this.num並沒有指向方法say中定義的num,這裡的this還是指向了Test類,顯然我們是可以通過對象本身來訪問靜態資源的。
最後
感謝你看到這裡,看完有什麼的不懂的可以在評論區問我,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!