基礎 | 關鍵字static
考慮篇幅問題,Java基礎系列的「關鍵字static與final」部分將分兩次進行梳理,本次主要總結「static關鍵字」。
面試時也經常被問到「static關鍵字」的相關問題,如 「談談對static關鍵字的理解?static有哪幾種用法?靜態內部類與普通內部類有什麼區別?Java中變數的初始化順序是怎樣的?」,建議重點關注。
談談對關鍵字static的理解?
關鍵字static表示「靜態的」,主要思想是保證無論該類是否產生物件或無論產生多少物件的情況下,某些特定的資料在記憶體空間中只有一份。
在Java類中,可用static修飾屬性、方法、程式碼塊和內部類,而不能修飾構造器。
其中,被修飾後的成員具有如下特點:
- 隨著類的載入而載入,故優先於物件存在;
- 所修飾的成員,被該類的所有物件所共享;
- 訪問許可權允許時,可不建立物件,直接被類呼叫。
static有哪幾種用法?
關鍵字static大體上有一下五種用法:
- 靜態匯入
- 靜態變數
- 靜態方法
- 靜態程式碼塊
- 靜態內部類
靜態匯入:
靜態匯入極少使用,在梳理本篇文章之前真的不知道還有此奇技淫巧,僅作了解即可,示例程式碼如下:
// 靜態導包,在類中使用Math的靜態方法和屬性時可以省略「Math.」
import static java.lang.Math.*;
public class StaticImport {
public static void main(String[] args) {
double a = cos(PI / 2); //已省略「Math.」
double b = pow(2.4,1.2);
double r = max(a,b);
System.out.println(r);
}
}
當在程式中多次使用某型別的靜態成員(靜態屬性和靜態方法)時,即可使用靜態匯入,作用是將該型別的靜態成員引入到當前的名稱空間,那麼在程式中呼叫該型別的靜態成員時可以像呼叫本類內定義的成員一樣,直接呼叫,而無需採用「類名.靜態成員名」的方式。
缺點:雖然簡化程式碼,但可讀性大大降低,幾乎不使用。
靜態變數:
在Java類中,用static修飾的屬性為靜態變數(類變數或類屬性),而非static修飾的屬性為例項變數,區別如下:
靜態方法:
在Java類中,用static修飾的方法為靜態方法,也叫類方法,其與非靜態方法的對比如下:
注意:靜態的結構隨著類的載入而載入,其生命週期早於非靜態的結構,同時被回收也要晚於非靜態的結構。
靜態程式碼塊:
靜態程式碼塊僅在類載入時執行一次,主要用於對Java類的靜態變數(類屬性)進行初始化操作。
執行順序:靜態程式碼塊 > 構造程式碼塊(非靜態程式碼塊) > 構造方法。
靜態內部類:
內部類的一種,靜態內部類不依賴於外部類,即可以不依賴於外部類例項物件而被例項化,且不能訪問外部類的非靜態成員(屬性和方法)。
建議重點關注下一個問題「靜態內部類與普通內部類有什麼區別?」。
靜態內部類與普通內部類有什麼區別?
在物件建立方面,靜態內部類可以不依賴於外部類的例項物件而被例項化,而普通內部類需要在外部類例項化後才能進行例項化。示例程式碼如下:
// 設類ClassA有靜態內部類ClassB和普通內部類ClassC
ClassA classA = new ClassA();
ClassA.B classB = new ClassA.B();
ClassA.C classC = classA.new ClassC();
在是否能夠擁有靜態成員方面,靜態內部類可以擁有靜態成員,而普通內部類則不能擁有靜態成員。
在訪問外部類成員方面,靜態內部類只能訪問外部類的靜態成員,而非靜態內部類可以訪問外部類的所有成員。
備註:該問題在面試Synopsys安全軟體工程師職位時被問到過,一定要重點關注。
Java中變數的初始化順序是怎樣的?
在有繼承關係的情況下,變數初始化順序如下:
- 父類的靜態變數和靜態程式碼塊
- 子類的靜態變數和靜態程式碼塊
- 父類的例項變數和普通程式碼塊
- 父類的建構函式
- 子類的例項變數和普通程式碼塊
- 子類的建構函式
擴充套件問題:指出下面程式的執行結果
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
執行結果為:1a2b2b。建立物件時構造器的呼叫順序是:先初始化靜態成員,然後呼叫父類構造器,再初始化非靜態成員,最後呼叫自身構造器。
擴充套件面試題
問:靜態方法內部是否可呼叫非靜態方法?
答:不可以,靜態方法只能訪問靜態成員,因為非靜態方法的呼叫要先建立物件,在呼叫靜態方法時可能物件並沒有被初始化。
問:內部類可以引用它的包含類(外部類)的成員嗎?
答:靜態內部類只能訪問外部類的靜態成員,包括私有的;而普通內部類可以訪問外部類的所有成員,包括私有的。
推薦閱讀
歡迎關注
Java名企面試吧,每天10點24分,我們不見不散!
丙子先生的宗旨是,每天以短篇幅講高頻面試題,不增加太多負擔,但需要持之以恆。
能力有限,歡迎指教!