前幾天去面試,突然被問到Java關鍵字中的static和final,有點懵逼,有些概念性的東西竟然忘了,痛定思痛,故打算這樣一篇博客來複習一下。
一、static
靜態修飾符,可作用在變量、方法,方法塊,類(內部類),所對應的調用時機和調用次數有所不同,主要分爲以下幾種情況:
1、作用在變量和方法塊
public class ClassE {
static int a = 1;
static{
System.out.println("ClassE靜態代碼塊");
}
public ClassE() {
System.out.println("ClassE構造");
}
public static void main(String[] args) {
ClassE classE = new ClassE();
ClassE classE2 = new ClassE();
}
}
運行結果:
ClassE靜態方法塊
ClassE構造
ClassE構造
初始化一個類時,首先按代碼順序,初始化類中的靜態變量和執行類中的靜態代碼塊,然後在調用構造方法。但是應該注意的是,靜態變量的初始化和靜態代碼塊的執行,只會在第一次調用該類時執行僅有的一次!!
此外,如果調用類中的靜態方法,也會先執行該類中所有靜態變量的初始化和靜態代碼塊後,再調用該靜態方法,也是只會在第一次調用該類時執行僅有的一次(不管調用該類中任意一靜態方法,都只會在第一次調用時執行且只會執行一次),例如:
public class ClassE {
static int a = 1;
static{
System.out.println("ClassE靜態方法塊");
}
public ClassE() {
System.out.println("ClassE構造");
}
static void fun1(){
System.out.println("調用靜態方法1");
}
static void fun2(){
System.out.println("調用靜態方法2");
}
public static void main(String[] args) {
ClassE.fun1();
ClassE.fun2();
}
}
運行結果:
ClassE靜態方法塊
調用靜態方法1
調用靜態方法2
注意:不管靜態還是非靜態的變量都可以被子類繼承和覆蓋(即父類中定義一個靜態變量,可以通過子類進行調用)。
public class ClassB {
static int a = 1;
}
public class ClassA extends ClassB {
public static void main(String[] args) {
int z = ClassA.a;//合法操作
}
}
如果在子類中重寫該靜態變量,父類中該靜態變量就會被隱藏。
2、作用在方法
靜態方法,只要定義了類,不必建立類的實例就可使用。
public class ClassE {
public ClassE() {
}
static void fun1(){
System.out.println("調用靜態方法1");
}
void fun2(){
System.out.println("調用非靜態方法2");
}
public static void main(String[] args) {
ClassE.fun1();
ClassE classE = new ClassE();
classE.fun2();
}
}
靜態方法的繼承與靜態變量的繼承一致,可參照靜態變量的做法進行操作。注意,靜態方法中無法使用super關鍵字,所有有關於super關鍵字的一切操作都無實現。
3、靜態內部類
關鍵字static不能修飾外部類,只能修飾內部類。
public class ClassD {
static class ClassE{
public ClassE() {
System.out.println("靜態類構造方法");
}
void fun(){
System.out.println("靜態類構造方法");
}
}
public static void main(String[] args) {
ClassE classE = new ClassE();classE.fun();
}
}
靜態內部類的作用:爲了降低包的深度,方便類的使用,靜態內部類適用於包含類當中,但又不依賴與外在的類,只是爲了方便管理類結構而定義。在創建靜態內部類的時候,不需要外部類對象的引用。
靜態內部類和非靜態內部類區別:非靜態內部類可以調用外部類變量,靜態內部類不可以調用外部類非靜態變量。
4、靜態關鍵字Static對類初始化時調用代碼順序的影響
子Class繼承含有static關鍵字父Class,構造子Class對象時,代碼的執行順序:
//父類 public class ClassI { static int a = 1;//靜態變量 int b = 1;//全局變量 static{ System.out.println("父類的靜態代碼塊"); } public ClassI() { System.out.println("父類的構造方法"); } } //子類 public class ClassH extends ClassI{ static int c = 1; int d = 1;//全局變量 static{ System.out.println("子類的靜態代碼塊"); } public ClassH() { System.out.println("子類的構造方法"); } public static void main(String[] args) { ClassH classH = new ClassH(); } }
父類的靜態對象->子類的靜態對象->父類全局變量聲明和初始化->父類的構造函數->子類全局變量聲明和初始化->子類的構造函數
二、Final
該關鍵字用於表明不可修改或者不可繼承。可以作用於變量,方法,類
1、作用在類上面說明該類不可被繼承
2、作用在方法上,說明在繼承該類的子類不可修改該方法。
3、作用在變量上,說明該變量不可變(注意:在定義final類型的變量時,需要初始化該值,否則會報錯)
關鍵字final對代碼的調用順序沒有影響,用法也比關鍵字static簡單。