你見過老外的 Java 面試題嗎(下)?

前言

上一篇文章總結了 老外常見的 Java 面試題上,如果有感興趣的同學可以點擊查看,接下來補上下半部。

正文

finalize 方法調用了多少次

關於 finalize 總結了以下幾點:
  • finalize() 方法由垃圾收集器調用。對於每個對象,垃圾收集器只調用 finalize() 方法一次
  • finalize() 是 Object 的 protected 方法,子類可以覆蓋該方法以實現資源清理工作,GC 在回收對象之前調用該方法。
  • finalize() 與 C++ 中的析構函數不是對應的。C++ 中的析構函數調用的時機是確定的(對象離開作用域或delete 掉),但 Java 中的 finalize 的調用時機是不確定的
如何理解 finalize() 的調用時機?

當垃圾回收器要宣告一個對象死亡時,至少要經過兩次標記過程:

  • 如果對象在進行可達性分析後發現沒有和 GC Roots 相連接的引用鏈,就會被第一次標記,並且判斷是否執行 finalize() 方法。
  • 如果對象覆蓋 finalize( ) 方法且未被虛擬機調用過,那麼這個對象會被放置在 F-Queue 隊列中,並在稍後由一個虛擬機自動建立的低優先級的 Finalize 線程區執行觸發 finalize() 方法,但不承諾等待其運行結束。

finalization 的目的:對象逃脫死亡的最後一次機會。(只要重新與引用鏈上的任何一個對象建立關聯即可。)但是不建議使用,運行代價高昂,不確定性大,且無法保證各個對象的調用順序。

可用try-finally或其他替代。

this 和 super 關鍵字可以同時調用嗎

  • super 從子類中調用父類的構造方法,this() 在同一類內調用其它方法。
  • 儘管可以用 this 調用一個構造器,但卻不能調用兩個
  • this 和 super 不能同時出現在一個構造函數裏面,因為 this 必然會調用其它的構造函數其它的構造函數必然也會有 super 語句的存在,所以在同一個構造函數裏面有相同的語句,就失去了語句的意義
  • 從本質上講,this 是一個指向本對象的指針, 然而 super 是一個Java關鍵字

你能在執行 main() 方法之前運行一個代碼嗎

在 Java 中,如果想在 main() 方法之前運行一段代碼,只需要定義一個 static {} 靜態代碼塊,就可以讓 static 里的代碼執行在 main() 方法之前。

public class staticFactory {
    static {
        System.out.println("static");
    }

    public static void main(String[] args) {
        System.out.println("main");
    }
}
// 輸出
// static  main

為什麼 Java 本質上是動態的

Java 本質為靜態語言,而不是動態語言。動態語言顯著的特點是在程序運行時,可以改變程序結構或變量類型,典型的動態語言有 Python、ruby、javascript 等。Java 不是動態語言,但 Java 具有一定的動態性,表現在以下幾個方面:

  • 反射機制
  • 動態位元組碼操作
  • 動態編譯
  • 執行其他腳本代碼

解釋下守護進程線程

在Java中有兩類線程:User Thread(用戶線程)Daemon Thread(守護線程)

  • 守護線程 是高優先級線程。JVM 會在終止之前等待任何用戶線程完成其任務
  • 用戶線程 是低優先級線程。其唯一作用是為用戶線程提供服務。

用個比較通俗的比如,任何一個守護線程都是整個 JVM 中所有非守護線程的保姆:

只要當前 JVM 實例中尚存在任何一個非守護線程沒有結束,守護線程就全部工作;只有當最後一個非守護線程結束時,守護線程隨着JVM一同結束工作。

User 和 Daemon 兩者幾乎沒有區別,唯一的不同之處就在於虛擬機的離開:如果 User Thread 已經全部退出運行了,只剩下 Daemon Thread 存在了,虛擬機也就退出了。 因為沒有了被守護者,Daemon 也就沒有工作可做了,也就沒有繼續運行程序的必要了。

如何實現一個守護線程?
NewThread daemonThread = new NewThread();
daemonThread.setDaemon(true);
daemonThread.start();

使用守護線程有幾點需要注意:

  • thread.setDaemon(true) 必須在 thread.start() 之前設置,否則會跑出一個 IllegalThreadStateException異常。你不能把正在運行的常規線程設置為守護線程。
  • 在 Daemon 線程中產生的新線程也是 Daemon 的。
  • 不要認為所有的應用都可以分配給 Daemon 來進行服務,比如讀寫操作或者計算邏輯。

解釋 >> 和 >>> 運算符之間的區別

雖然它們看上去比較像,但兩者之間區別還是很大的。

>> 按位右移運算符。左操作數按位右移右操作數指定的位數。 即:A >> 2得到15即 1111
>>> 按位右移補零操作符。左操作數的值按右操作數指定的位數右移,移動得到的空位以零填充。即:A>>>2得到15即0000 1111

我們能重載一個靜態方法嗎

java 的靜態方法不能被重寫。 靜態成員(方法或屬性)是類的成員存放在棧中,類可以直接調用(是屬於類的靜態成員,當然對象也可以調用,只是說你可以使用而已);實例成員是對象的成員,存放在堆中,只能被對象調用。 重寫的目的在於根據創造對象的所屬類型不同而表現出多態

總結:

以上就是總結的剩餘的面試題,其實和我們平時的面試題還是有一些差距。不過在整理面試題的時候,有一個題的答案非常有爭議,網上也是怎麼討論的都有,所以準備單獨拿出有爭議的去分析。