<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # Java 核心面試問題 – 第 2 部分 > 原文: [https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-2/](https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-2/) 在 [Java 面試問題系列:第 1 部分](//howtodoinjava.com/java/interviews-questions/core-java-interview-questions-series-part-1/ "Core java interview questions series : Part 1")中,我們討論了面試官通常問的一些重要問題。 現在是推進該討論的時候了。 在這篇文章中,我將在下面給出的問題列表中進行討論。 ```java Why finalize() method should be avoided? Why HashMap should not be used in multithreaded environment? Can it cause infinite loop as well? Explain abstraction and encapsulation? How are they related? Difference between interfaces and abstract classes? How StringBuffer save the memory? Why wait and notify is declared in Object class instead of Thread ? Write Java program to create deadlock in Java and fix it ? What happens if your Serializable class contains a member which is not serializable? How do you fix it? Explain transient and volatile keywords in java? Difference between Iterator and ListIterator? ``` ## 為什么要避免使用`finalize()`方法? 我們都知道,在回收分配給對象的內存之前,垃圾收集器線程會調用[`finalize()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#finalize--)方法的基本聲明。 請參閱[這篇文章](//howtodoinjava.com/java/related-concepts/why-not-to-use-finalize-method-in-java/ "Why not to use finalize() method in java"),證明根本不能保證`finalize()`調用。 其他原因可能是: 1. `finalize()`方法無法像構造器一樣在鏈接中工作。 這意味著就像您調用構造器時一樣,所有超類的構造器都將被隱式調用。 但是,在使用`finalize`方法的情況下,則不遵循此方法。 超類的`finalize()`應該顯式調用。 2. 由`finalize`方法引發的任何異常都將被 GC 線程忽略,并且不會進一步傳播,實際上不會記錄在日志文件中。 真糟糕,不是嗎? 3. 另外,當您的類中包含`finalize()`時,也會影響性能。 Joshua bloch 在《Effective Java》(第 2 版)中說, “哦,還有一件事:使用終結器會嚴重影響性能。 在我的機器上,創建和銷毀簡單對象的時間約為 5.6 ns。 添加終結器會將時間增加到 2,400 ns。 換句話說,使用終結器創建和銷毀對象要慢 430 倍。” ## 為什么不應該在多線程環境中使用`HashMap`? 它也會引起無限循環嗎? 我們知道`HashMap`是非同步集合,因為它的同步計數器是`HashTable`。 因此,當您在多線程環境中訪問集合時,所有線程都在訪問集合的單個實例時,出于各種明顯的原因,例如`HashTable`,使用`HashTable`更安全。 以避免臟讀并保持數據一致性。 在最壞的情況下,這種多線程環境也可能導致無限循環。 是的,它是真實的。 `HashMap.get()`可能導致無限循環。 讓我們看看如何? 如果查看[`HashMap.get(Object key)`](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java)方法的源代碼,則如下所示: ```java public Object get(Object key) { Object k = maskNull(key); int hash = hash(k); int i = indexFor(hash, table.length); Entry e = table[i]; while (true) { if (e == null) return e; if (e.hash == hash &amp;&amp; eq(k, e.key)) return e.value; e = e.next; } } ``` 在多線程環境中,`while(true){...}`始終是運行時無限循環的受害者,因此`e.next`可以指向自身。 這將導致無限循環。 但是,`e.next`將如何指向自身(即)。 這可能在`void transfer(Entry[] newTable)`方法中發生,該方法在`HashMap`調整大小時調用。 ```java do { Entry next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); ``` 如果調整大小并且同時其他線程試圖修改映射實例,則這段代碼很容易產生上述條件。 避免這種情況的唯一方法是在代碼中使用同步,或者更好的方法是使用同步集合。 ## 解釋抽象和封裝? 它們有什么關系? #### 抽象 [抽象](//howtodoinjava.com/object-oriented/understanding-abstraction-in-java/)僅捕獲與當前視角有關的那些對象的詳細信息。 在[面向對象編程](//howtodoinjava.com/object-oriented/object-oriented-principles/)理論中,抽象涉及定義定義代表抽象“角色”的對象的功能,這些抽象“角色”可以執行工作,報告和更改其狀態,并與系統中的其他對象“通信”。 任何編程語言中的抽象都可以通過多種方式工作。 從創建子例程到定義用于進行低級語言調用的接口可以看出。 一些抽象試圖通過完全隱藏它們依次建立在其上的抽象,來限制程序員所需概念的廣度。 例如設計模式。 通常,可以通過兩種方式查看抽象: **數據抽象**是創建復雜數據類型并僅公開有意義的操作以與數據類型進行交互的方法,其中隱藏了外部工作中的所有實現細節。 **控制抽象**是識別所有此類語句并將其作為工作單元公開的過程。 我們通常在創建函數來執行任何工作時使用此功能。 #### 封裝 將類中的數據和方法與實現隱藏(通過訪問控制)結合起來通常稱為封裝。 結果是具有特征和行為的數據類型。 封裝本質上既具有信息隱藏又具有實現隱藏。 “***無論進行任何更改,都封裝它***”。 它被引用為著名的設計原則。 因此,在任何類中,運行時中的數據都可能發生更改,將來的發行版中可能會更改實現。 因此,封裝既適用于數據也適用于實現。 因此,它們可以像下面這樣關聯: - 抽象更多是關于“類可以做什么”。(想法) - 封裝更多地是關于“如何”實現該功能。(實現) ## 接口和抽象類之間的區別? 接口和抽象類之間的基本區別可以算作如下: * 接口不能有任何方法,而抽象類可以(在 [Java8 默認方法](//howtodoinjava.com/java8/default-methods-in-java-8/)之后不正確) * 一個類可以實現許多接口,但只能有一個超類(是否抽象) * 接口不屬于類層次結構。 不相關的類可以實現相同的接口 您應該記住:“當您可以用***做什么***充分描述該概念時,而無需指定任何***它是如何工作的***,那么您應該使用一個接口。 如果您需要包括一些實現細節,那么您將需要在抽象類中表示您的概念。” 另外,如果我說的不同:是否可以將許多*分組在一起并用一個名詞描述的類? 如果是這樣,請以該名詞的名稱創建一個抽象類,并從其繼承這些類。 例如,`Cat`和`Dog`都可以從抽象類`Animal`繼承,并且此抽象基類將實現方法`void breathe()`,所有動物都將以完全相同的方式執行該方法。* 什么樣的動詞可以應用于我的類,通常也可以應用于其他動詞? 為每個動詞創建一個接口。 例如,所有動物都可以喂食,因此我將創建一個名為`IFeedable`的接口,并讓`Animal`實現該接口。 盡管`Dog`和`Horse`足以實現`ILikeable`,但有些還不夠。 正如某人所說:主要區別在于您想要實現的地方。 通過創建接口,可以將實現移動到實現接口的任何類。 通過創建一個抽象類,您可以在一個中央位置共享所有派生類的實現,并且避免了很多不好的事情,例如代碼重復。 ## `StringBuffer`如何節省內存? [字符串](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html)被實現為[不變對象](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/); 也就是說,當您最初決定將某些內容放入`String`對象時,JVM 會分配一個與初始值大小正好相等的固定寬度數組。 然后將其視為 JVM 內部的常量,在不更改`String`值的情況下,可以大大節省性能。 但是,如果您決定以任何方式更改`String`的內容,那么 JVM 實質上要做的就是將原始`String`的內容復制到一個臨時空間中,進行更改,然后將這些更改保存到一個全新的內存陣列中。 因此,在初始化后更改`String`的值是一項相當昂貴的操作。 [`StringBuffer`](https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html)在 JVM 內部被實現為可動態增長的數組,這意味著任何更改操作都可以在現有內存位置上進行,而新內存僅按需分配。 但是,JVM 沒有機會圍繞`StringBuffer`進行優化,因為假定其內容在任何情況下都是可更改的。 ## 為什么在對象類而不是線程中聲明了`wait`和`notify`? [`wait`,`notify`,`notifyAll`方法](//howtodoinjava.com/java/multi-threading/how-to-work-with-wait-notify-and-notifyall-in-java/)僅在您希望線程訪問共享資源并且共享資源可以是堆上的任何 Java 對象時才需要。 因此,這些方法是在核心`Object`類上定義的,因此每個對象都可以控制允許線程在其監視器上等待。 Java 沒有用于共享公共資源的任何特殊對象。 沒有定義這樣的數據結構。因此,在`Object`類上有責任成為共享資源,條件是它可以使用`wait()`,`notify()`和`notifyAll()`之類的輔助方法。 Java 基于 [Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) 的監視器概念。 在 Java 中,所有對象都有一個監視器。 線程在監視器上等待,因此要執行等待,我們需要 2 個參數: – 線程 – 監視器(任何對象) 在 Java 設計中,無法指定線程,它始終是當前運行代碼的線程。 但是,我們可以指定監視器(這是我們稱為`wait`的對象)。 這是一個很好的設計,因為如果我們可以讓任何其他線程在所需的監視器上等待,則會導致“入侵”,給設計/編程并發程序帶來了困難。 請記住,在 Java 中,不推薦使用會干擾另一個線程執行的所有操作(例如`stop()`)。 ## 編寫 Java 程序以在 Java 中創建死鎖并修復死鎖? 在 Java 中,死鎖是指至少有兩個線程在某個不同的資源上持有鎖,并且都在等待其他資源來完成其任務的情況。 而且,沒有人能夠鎖定它所擁有的資源。 > 閱讀更多:[編寫死鎖并使用 Java 解決](//howtodoinjava.com/java/multi-threading/writing-a-deadlock-and-resolving-in-java/ "Writing a deadlock and resolving in java") ## 如果您的`Serializable`類包含一個不可序列化的成員,該怎么辦? 您如何解決? 在這種情況下,將在運行時引發`NotSerializableException`。 要解決此問題,一個非常簡單的解決方案是將此類字段標記為瞬態。 這意味著這些字段將不會被序列化。 如果還要保存這些字段的狀態,則應考慮已經實現[`Serializable`](https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html)接口的引用變量。 您可能還需要使用`readResolve()`和`writeResolve()`方法。 讓我們總結一下: * 首先,設置您的不可序列化字段`transient`。 * 在`writeObject()`中,首先在流上調用`defaultWriteObject()`來存儲所有非瞬態字段,然后調用其他方法來序列化不可序列化對象的各個屬性。 * 在`readObject()`中,首先在流上調用`defaultReadObject()`以讀回所有非瞬態字段,然后調用其他方法(與您添加到`writeObject`的方法相對應)來反序列化不可序列化的對象。 另外,我強烈建議閱讀[**關于 Java**](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java") 中序列化的完整指南。 ## 解釋 Java 中的`transient`和`volatile`關鍵字? #### `transient` “*Java 中的`transient`關鍵字用于指示不應序列化字段。*”根據語言規范:可以將變量標記為`transient`,以指示它們不是對象持久狀態的一部分。 例如,您可能具有從其他字段派生的字段,并且僅應以編程方式進行操作,而不要通過序列化來保持狀態。 例如,在`BankPayment.java`類中,可以對`principal`和`rate`之類的字段進行序列化,而即使在反序列化之后也可以隨時計算`interest`。 回想一下,java 中的每個線程也都有自己的本地內存空間,并且它在本地內存中執行所有讀/寫操作。 完成所有操作后,它將所有線程訪問該變量的位置寫回主存儲器中變量的修改狀態。 通常,這是 JVM 內部的默認流程。 但是,`volatile`修飾符告訴 JVM,訪問該變量的線程必須始終將其自身的變量私有副本與內存中的主副本進行協調。 這意味著每次線程想要讀取變量的狀態時,它都必須刷新其本地內存狀態并從主內存中更新變量。 #### `volatile` `volatile`在無鎖算法中最有用。 當您不使用鎖定來訪問該變量并且希望一個線程所做的更改在另一個線程中可見時,或者您要創建“后接”關系以確保計算無需重新排序,以確保更改在適當的時間可見。 `volatile`應該用于在多線程環境中安全發布不可變對象。 聲明諸如`public volatile ImmutableObject foo`之類的字段可確保所有線程始終看到當前可用的實例引用。 ## `Iterator`和`ListIterator`之間的區別? 我們可以使用`Iterator`遍歷`Set`或`List`或`Map`。 但是`ListIterator`僅可用于遍歷`List`。 其他差異如下所示。 您可以: 1. 向后迭代。 2. 隨時獲取索引。 3. 隨時添加新值。 4. 在這個時間設置一個新值。 例如: ```java List<String> names = new ArrayList<String>(); names.add("Alex"); names.add("Bob"); names.add("Charles"); System.out.println(names); ListIterator<String> listIterator = names.listIterator(); //Add a value at any place using ListIterator while(listIterator.hasNext()){ listIterator.next(); listIterator.add("Lokesh"); } System.out.println(names); listIterator = names.listIterator(); //Set a value at any place using ListIterator while(listIterator.hasNext()){ listIterator.next(); listIterator.set("John"); } System.out.println(names); Output: [Alex, Bob, Charles] [Alex, Lokesh, Bob, Lokesh, Charles, Lokesh] [John, John, John, John, John, John] ``` 顯然,我可以在列表中的任意位置添加元素,同時對其進行迭代 – 同樣,我也可以更改任何元素。 使用`Iterator`不可能。 學習愉快!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看