問:談?wù)?Java 中 final、finally豪嗽、finalize 的區(qū)別谴蔑?
答:
final 是一個修飾符,如果一個類被聲明為 final 則其不能再派生出新的子類龟梦,所以一個類不能既被聲明為 abstract 又被聲明為 final 的隐锭;將變量或方法聲明為 final 可以保證它們在使用中不被改變(對于對象變量來說其引用不可變,即不能再指向其他的對象变秦,但是對象的值可變)成榜,被聲明為 final 的變量必須在聲明時給定初值,而在以后的引用中只能讀取不可修改蹦玫,被聲明為 final 的方法也同樣只能使用不能重載赎婚。使用 final 關(guān)鍵字如果編譯器能夠在編譯階段確定某變量的值則編譯器就會把該變量當做編譯期常量來使用,如果需要在運行時確定(譬如方法調(diào)用)則編譯器就不會優(yōu)化相關(guān)代碼樱溉;將類挣输、方法、變量聲明為 final 能夠提高性能福贞,這樣 JVM 就有機會進行估計并進行優(yōu)化撩嚼;接口中的變量都是 public static final 的。
finally 用來在異常處理時提供塊來執(zhí)行任何清除操作,如果拋出一個異常完丽,則相匹配的 catch 子句就會執(zhí)行恋技,然后控制就會進入 finally 塊。
finalize 是一個方法名逻族,Java 允許使用 finalize() 方法在垃圾收集器將對象從內(nèi)存中清除出去之前做必要的清理工作蜻底,這個方法是由垃圾收集器在確定這個對象沒有被引用時對這個對象調(diào)用的,它是在 Object 類中定義的聘鳞,因此所有的類都繼承了它薄辅,子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作,finalize() 方法在垃圾收集器刪除對象之前對這個對象調(diào)用抠璃。
問:java 中 static站楚、final、static final 的區(qū)別是什么搏嗡?
答:
final 可以修飾屬性窿春、方法、類采盒、局部變量(方法中的變量)谁尸,修飾屬性的初始化可以在編譯期,也可以在運行期纽甘,初始化后不能被改變良蛮;修飾的屬性表明是一個常數(shù);修飾方法表示方法不能在子類中被重寫悍赢;修飾類表示類不能被繼承决瞳。
static 可以修飾屬性、方法左权、代碼段皮胡、內(nèi)部類(靜態(tài)內(nèi)部類或嵌套內(nèi)部類),修飾屬性的初始化在編譯期(類加載的時候)赏迟,初始化后可以被修改值屡贺;修飾的屬性、方法锌杀、代碼段跟該類的具體對象無關(guān)甩栈,不創(chuàng)建對象也能調(diào)用 static 修飾的屬性、方法等糕再;static 不可以修飾局部變量量没。
static final(或者 final static)是組合修飾,static 修飾的屬性強調(diào)它們只有一個突想,final 修飾的屬性表明是一個常數(shù)(創(chuàng)建后不能被修改)殴蹄,static final 修飾的屬性表示一旦給值就不可修改并且可以通過類名訪問究抓,static final 也可以修飾方法,表示該方法不能重寫袭灯,可以在不 new 對象的情況下調(diào)用刺下。
問:下面程序的有問題嗎,結(jié)果是什么稽荧?
class Test {
public static String foo() {
System.out.println("foo called.");
return "return called.";
}
}
public class Demo {
public static void main(String[] args) {
Test obj = null;
System.out.println(obj.foo());
}
}
答:沒有問題怠李,運行結(jié)果如下:
foo called.
return called.
因為 jvm 內(nèi)存里有棧區(qū)、堆區(qū)蛤克,棧區(qū)主要用來存放基礎(chǔ)類型數(shù)據(jù)和局部變量,堆區(qū)主要存放 new 出來的對象夷蚊,在堆區(qū)又有一個叫做方法區(qū)的內(nèi)存區(qū)域用來存放常量构挤、static 變量和 static 方法、還有類的信息惕鼓,static 的變量和方法不依賴對象筋现,即使對象沒有創(chuàng)建,在類加載的時候已經(jīng)存在信息了(Test 在聲明時就被加載了)箱歧,jvm 識別出是 static 方法就直接調(diào)用了在方法區(qū)內(nèi)存里的方法矾飞,沒有報空指針異常。
問:下面程序的運行結(jié)果是什么呀邢?為什么洒沦?
public class Test {
public static void main(String[] args) {
String a = "hello2";
final String b = "hello";
String c = b + 2;
String d = "hello";
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
}
答:運行結(jié)果如下:
true
false
因為當 final 變量是基本數(shù)據(jù)類型以及 String 類型時如果在編譯期間能知道它的確切值則編譯器會把它當做編譯期常量使用,也就是說在用到該 final 變量的地方相當于直接訪問了這個常量价淌,不需要在運行時確定申眼,所以上面代碼中由于變量 b 被 final 修飾從而被當做編譯器常量,故在使用到 b 的地方會直接將變量 b 替換為它的值蝉衣,而對于變量 d 的訪問卻需要在運行時通過鏈接來進行括尸。