Java關(guān)鍵字static的6個常見誤區(qū)及解決方法
static 是 Java 入門最早接觸、卻也是誤解最多的關(guān)鍵字。很多同學只會用它寫靜態(tài)常量、靜態(tài)方法,但對生命周期、繼承、重寫、初始化順序、this 能否使用、線程安全等認知模糊,日常寫 Bug、面試翻車,大多都是踩了 static 的坑。
誤區(qū)一:static 屬于對象,而不是屬于類
錯誤認知
靜態(tài)變量、靜態(tài)方法是歸每個對象所有,創(chuàng)建越多實例,靜態(tài)變量就有多份副本。
正確原理
1. static 修飾的成員,全局只一份,歸屬于類,不屬于任何對象。
2. 類加載階段就初始化,優(yōu)先于對象存在,所有實例共享同一個靜態(tài)變量。
3. 無論 new 多少個對象,靜態(tài)變量內(nèi)存中永遠只有一份。
反例代碼
public class StaticDemo {
public static int count = 0;
public StaticDemo(){
count++;
}
}連續(xù) new 三次對象,count 直接累加到 3,而不是每個對象各自為 1。
結(jié)論
靜態(tài)資源全局唯一、對象共享,跟實例數(shù)量無關(guān)。
誤區(qū)二:靜態(tài)方法可以被重寫(Override)
錯誤認知
父類有靜態(tài)方法,子類寫一個同名同參靜態(tài)方法,就是重寫。
正確原理
1. 靜態(tài)方法不能被重寫,只能被隱藏(Hide)。
2. 靜態(tài)方法編譯期靜態(tài)綁定,由引用類型決定調(diào)用哪個方法,而不是運行時對象類型。
3. 多態(tài)對 static 完全失效。
示例對比
class Father{
public static void show(){
System.out.println("父類靜態(tài)方法");
}
}
class Son extends Father{
public static void show(){
System.out.println("子類靜態(tài)方法");
}
}
public class Test{
public static void main(String[] args) {
Father f = new Son();
f.show(); // 輸出:父類靜態(tài)方法
}
}如果是普通實例方法,會走多態(tài)調(diào)用子類;靜態(tài)方法看引用類型,不看實際對象。
結(jié)論
靜態(tài)方法只可隱藏、不可重寫,不具備多態(tài)特性。
誤區(qū)三:靜態(tài)方法中可以直接使用 this、super
錯誤認知
普通方法能用 this,靜態(tài)方法也能用 this 訪問成員。
正確原理
1. this、super 代表當前實例對象。
2. 靜態(tài)方法屬于類,不需要對象就能調(diào)用,執(zhí)行時可能根本沒有實例。
3. 因此靜態(tài)方法禁止使用 this、super,也不能直接調(diào)用普通實例方法、直接訪問實例變量。
編譯報錯代碼
public static void test(){
this.xxx(); // 編譯直接報錯
}結(jié)論
靜態(tài)上下文與實例無關(guān),不能出現(xiàn)任何對象相關(guān)關(guān)鍵字。
誤區(qū)四:靜態(tài)代碼塊只會執(zhí)行一次,隨便寫都沒問題
錯誤認知
靜態(tài)代碼塊隨時都會執(zhí)行,或者每次 new 對象都會執(zhí)行。
正確原理
1. 靜態(tài)代碼塊:類加載時執(zhí)行,全局只執(zhí)行一次。
2. 執(zhí)行時機早于構(gòu)造器、早于普通代碼塊。
3. 只會在類首次被加載、主動使用時觸發(fā)一次,后續(xù) new 對象不再執(zhí)行。
4. 坑:靜態(tài)塊里不要寫耗時邏輯、數(shù)據(jù)庫連接、死循環(huán),會直接拖慢項目啟動、導致卡死。
執(zhí)行順序
靜態(tài)代碼塊 → 普通代碼塊 → 構(gòu)造方法
結(jié)論
靜態(tài)塊隨類加載只跑一次,適合初始化常量、加載配置,禁止寫耗時業(yè)務邏輯。
誤區(qū)五:static 變量天然線程安全
錯誤認知
靜態(tài)變量全局只有一份,自帶同步,多線程修改也不會有并發(fā)問題。
正確原理
1. static 只是全局共享一份內(nèi)存,不具備任何原子性、可見性、有序性保障。
2. 多線程同時讀寫靜態(tài)變量,依然會出現(xiàn)臟數(shù)據(jù)、覆蓋丟失、競態(tài)條件。
3. 靜態(tài)變量反而更容易引發(fā)并發(fā) Bug,因為所有線程共享同一份。
并發(fā)錯誤示例
public class CountUtil{
public static int num = 0;
public static void add(){
num++;
}
}多線程循環(huán)累加,結(jié)果一定小于預期,典型線程不安全。
正確做法
靜態(tài)變量并發(fā)修改需要:synchronized / AtomicInteger / Lock 保證線程安全。
結(jié)論
static ≠ 線程安全,共享變量反而更容易出并發(fā)問題。
誤區(qū)六:可以在普通代碼塊/構(gòu)造器中給靜態(tài)變量隨意初始化
錯誤認知
靜態(tài)變量在哪賦值都一樣,構(gòu)造器、普通代碼塊隨便改。
正確原理
1. 靜態(tài)變量屬于類,本該在:靜態(tài)代碼塊、聲明處初始化。
2. 在構(gòu)造器、普通代碼塊給靜態(tài)變量賦值:
- 每 new 一次對象,就會重新覆蓋靜態(tài)值;
- 極易造成全局狀態(tài)被意外篡改,隱藏極深的 Bug。
3. 違背設計語義:靜態(tài)資源不該依賴實例創(chuàng)建來初始化。
坑示例
public class User{
public static String type;
public User(){
type = "user";
}
}只要 new 一次,就強行覆蓋靜態(tài)變量,全局狀態(tài)被隨意改動。
結(jié)論
靜態(tài)變量盡量在聲明或靜態(tài)塊初始化,不要在構(gòu)造器、實例代碼塊中賦值。
全文總結(jié)
這 6 個誤區(qū),既是日常開發(fā)高頻坑,也是 Java 面試常問原題。
1. static 歸類不歸對象,全局唯一共享;
2. 靜態(tài)方法不可重寫、只能隱藏,無多態(tài);
3. 靜態(tài)上下文不能用 this / super,不能直接訪問實例成員;
4. 靜態(tài)代碼塊類加載僅執(zhí)行一次,禁止耗時邏輯;
5. static 變量不自帶線程安全,多線程必須加同步;
6. 靜態(tài)變量盡量靜態(tài)環(huán)境初始化,不要在構(gòu)造器中亂賦值。
以上就是Java關(guān)鍵字static的6個常見誤區(qū)及解決方法的詳細內(nèi)容,更多關(guān)于Java static關(guān)鍵字常見誤區(qū)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中comparator接口和Comparable接口的比較解析
這篇文章主要介紹了Java中comparator接口和Comparable接口的比較解析,Java提供了一個用于比較的接口Comparator和Comparable接口,提供了一個比較的方法,所有實現(xiàn)該接口的類,都動態(tài)的實現(xiàn)了該比較方法,需要的朋友可以參考下2023-08-08
Jedis出現(xiàn)connection timeout問題解決方法(JedisPool連接池使用實例)
這篇文章主要介紹了Jedis出現(xiàn)connection timeout問題解決方法,使用Jedis的JedisPool連接池解決了這個問題,需要的朋友可以參考下2014-05-05
簡單了解JAVA public class與class區(qū)別
這篇文章主要介紹了簡單了解JAVA public class與class區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03
SpringBoot3整合SpringDoc實現(xiàn)在線接口文檔的詳細過程
這篇文章主要介紹了SpringBoot3整合SpringDoc實現(xiàn)在線接口文檔的詳細過程,本文通過示例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-06-06

