JavaRush /Java Blog /Random-TW /Java 開發者訪談問答分析。第 14 部分

Java 開發者訪談問答分析。第 14 部分

在 Random-TW 群組發布
焰火!世界不斷在變化,我們也在不斷變化。以前,要成為Java開發人員,了解一點Java語法就夠了,剩下的就來了。隨著時間的推移,成為 Java 開發人員所需的知識水平顯著提高,競爭也不斷加劇,這繼續將所需知識的下限推高。 Java 開發者訪談問答分析。 第 14 - 1 部分如果你真的想成為一名開發者,你需要理所當然地做好充分的準備,才能在像你這樣的初學者中脫穎而出,我們今天要做的就是繼續分析這250+個問題。在之前的文章中,我們討論了所有初級級別的問題,今天我們將討論中級級別的問題。雖然我注意到這些不是100%的中級問題,但你可以在初級面試中遇到大部分問題,因為正是在這樣的面試中,對你的理論基礎進行了詳細的探究,而對於中學生來說問題更著重於探究他的經驗。 Java 開發者訪談問答分析。 第 14 - 2 部分但是,事不宜遲,讓我們開始吧。

中間

是常見的

1. 與過程式/函數式程式設計相比,OOP 的優點和缺點是什麼?

Juinior的題分析中有這個問題,所以我已經回答了。在本文的 這一部分(問題 16 和問題 17)中找出這個問題及其答案。

2. 聚合與組合有何不同?

在 OOP 中,物件之間存在著多種類型的交互,統一在「Has-A 關係」的一般概念下。這種關係表示一個物件是另一個物件的組件。同時,這種關係有兩種子類型: 組合- 一個對象創建另一個對象,另一個對象的生命週期取決於創建者的生命週期。 聚合-一個物件在建構過程中接收到另一個物件的連結(指標)(在這種情況下,另一個物件的生命週期不依賴創建者的生命週期)。為了更好地理解,我們來看一個具體的例子。我們有一個特定的汽車類別 - Car,它又具有類型的內部字段 - Engine乘客列表 - List<Passenger>,它還有一個啟動移動的方法 - startMoving()
public class Car {

 private Engine engine;
 private List<Passenger> passengers;

 public Car(final List<Passenger> passengers) {
   this.engine = new Engine();
   this.passengers = passengers;
 }

 public void addPassenger(Passenger passenger) {
   passengers.add(passenger);
 }

 public void removePassengerByIndex(Long index) {
   passengers.remove(index);
 }

 public void startMoving() {
   engine.start();
   System.out.println("Машина начала своё движение");
   for (Passenger passenger : passengers) {
     System.out.println("В машине есть пассажир - " + passenger.getName());
   }
 }
}
在這種情況下,Composition是CarEngine之間的連接,因為汽車的性能直接取決於引擎物件的存在,因為如果engine = null,那麼我們將收到一個NullPointerException。反過來,如果沒有機器,引擎就無法存在(為什麼我們需要沒有機器的引擎?),並且不能在一個時間點屬於多個機器。這意味著,如果我們刪除Car對象,將不再有對Engine對象的引用,而且它很快就會被垃圾收集器刪除。正如您所看到的,這種關係非常嚴格(強)。 聚合是CarPassenger之間的連接,因為Car的效能絕不取決於Passenger類型的物件及其數量。他們可以離開汽車 - removePassengerByIndex(Long index)或輸入新的汽車 - addPassenger(Passenger乘客),儘管如此,汽車將繼續正常運行。反過來,Passenger物件可以在沒有Car物件的情況下存在。如您所知,這種聯繫比我們在構圖中看到的要弱得多。 Java 開發者訪談問答分析。 第 14 - 3 部分但這還不是全部,透過聚合連接到另一個物件的物件也可以在同一時間點與其他物件具有給定的連接。例如,您作為一名 Java 學生,同時註冊了英語、OOP 和對數課程,但同時您並不是其中至關重要的一部分,沒有這些課程就不可能正常運作(例如一位老師)。

3. 您在實務上使用過哪些 GoF 模式?舉例說明。

這個問題我之前已經回答過,所以就留下分析鏈接,看第一個問題。我還發現了一篇關於設計模式的精彩備忘錄文章,我強烈建議您保留它。

4.什麼是代理對象?舉例說明

代理是一種結構設計模式,允許您替換特殊的替代對象,或者換句話說,代理對象,而不是真實的對象。這些代理物件會攔截對原始物件的調用,允許在調用傳遞給原始物件 之前之後插入一些邏輯。Java 開發者訪談問答分析。 第 14 - 4 部分使用代理物件的範例:
  • 作為遠端代理 - 當我們需要在本地表示的遠端物件(不同地址空間中的物件)時使用。在這種情況下,代理將處理連接建立、編碼、解碼等,而客戶端將使用它,就好像它是位於本地空間的原始物件一樣。

  • 作為虛擬代理 - 在需要資源密集型物件時使用。在這種情況下,代理物件就像實際還不存在的真實物件的圖像一樣。當真正的請求(方法呼叫)傳送到該物件時,才會載入原始物件並執行該方法。這種方法也稱為延遲初始化;這非常方便,因為在某些情況下原始物件可能沒有用,那麼創建它就不需要任何成本。

  • 作為安全代理 - 當您需要根據客戶端權限控制對某些物件的存取時使用。也就是說,如果缺少存取權限的客戶端嘗試存取原始對象,代理將攔截它並且不允許它。

讓我們來看一個虛擬代理的範例:我們有一些處理程序介面:
public interface Processor {
 void process();
}
其實作使用了太多資源,但同時可能不會在每次啟動應用程式時使用:
public class HiperDifficultProcessor implements Processor {
 @Override
 public void process() {
   // некоторый сверхсложная обработка данных
 }
}
代理類別:
public class HiperDifficultProcessorProxy implements Processor {
private HiperDifficultProcessor processor;

 @Override
 public void process() {
   if (processor == null) {
     processor = new HiperDifficultProcessor();
   }
   processor.process();
 }
}
讓我們在main中運行它:
Processor processor = new HiperDifficultProcessorProxy();
// тут тяжеловсеного оригинального an object, ещё не сущетсвует
// но при этом есть an object, который его представляет и у которого можно вызывать его методы
processor.process(); // лишь теперь, an object оригинал был создан
我注意到許多框架都使用代理,對於Spring來說這是一個關鍵模式(Spring 內外都與它縫合在一起)。請在此處閱讀有關此模式的更多資訊。 Java 開發者訪談問答分析。 第 14 - 5 部分

5. Java 8 宣布了哪些創新?

Java 8帶來的創新如下:
  • 新增了功能接口,了解這是什麼樣的野獸

  • Lambda 表達式與函數式介面密切相關,請在此處閱讀有關其使用的更多資訊。

  • 新增了Stream API以方便處理資料集合,請在此處閱讀更多內容。

  • 新增了方法的連結

  • forEach()方法已新增至Iterable介面。

  • java.time套件中新增了新的日期和時間API,詳細分析請參閱這裡

  • 改進了並發 API

  • 添加一個可選包裝類,用於正確處理空值,您可以在此處找到有關此主題的優秀文章。

  • 新增介面使用靜態預設方法的能力(本質上,這使 Java 更接近多重繼承),更多詳細資訊請參閱此處

  • Collection(removeIf(), spliterator())類別中新增了新方法。

  • 對 Java Core 的細微改進。

Java 開發者訪談問答分析。 第 14 - 6 部分

6. 什麼是高內聚和低耦合?舉例說明。

高內聚高內聚是指某個類別包含彼此密切相關並為其目的組合的元素的概念。例如,User類別中的所有方法都應該代表使用者行為。如果類別包含不相關的元素,則該類別的內聚性較低。例如,包含電子郵件地址驗證方法的 User類別:
public class User {
private String name;
private String email;

 public String getName() {
   return this.name;
 }

 public void setName(final String name) {
   this.name = name;
 }

 public String getEmail() {
   return this.email;
 }

 public void setEmail(final String email) {
   this.email = email;
 }

 public boolean isValidEmail() {
   // некоторая логика валидации емейла
 }
}
使用者類別可能負責儲存使用者的電子郵件地址,但不負責驗證它或發送電子郵件。因此,為了實現高一致性,我們將驗證方法移至單獨的實用程式類別中:
public class EmailUtil {
 public static boolean isValidEmail(String email) {
   // некоторая логика валидации емейла
 }
}
我們根據需要使用它(例如,在保存用戶之前)。 低耦合低耦合是描述軟體模組之間低相互依賴性的概念。從本質上講,相互依賴是指改變一方就需要改變另一方。如果兩個類別密切相關,則它們具有強耦合(或緊密耦合)。例如,兩個具體類別儲存彼此的引用並呼叫彼此的方法。鬆散耦合的類別更容易開發和維護。由於它們彼此獨立,因此可以並行開發和測試。而且,它們可以更改和更新,而不會相互影響。讓我們來看一個強耦合類別的範例。我們有一些學生班:
public class Student {
 private Long id;
 private String name;
 private List<Lesson> lesson;
}
其中包含課程清單:
public class Lesson {
 private Long id;
 private String name;
 private List<Student> students;
}
每節課都包含一個參加學生的連結。非常強大的抓地力,你不覺得嗎?你怎樣才能減少它?首先,我們確保學生擁有的不是科目列表,而是其識別符列表:
public class Student {
 private Long id;
 private String name;
 private List<Long> lessonIds;
}
其次,課程班級不需要了解所有學生,所以我們把他們的名單全部刪除:
public class Lesson {
 private Long id;
 private String name;
}
所以事情變得容易多了,聯繫也變得弱了,你不覺得嗎? Java 開發者訪談問答分析。 第 14 - 7 部分

物件導向程式設計

7. Java中如何實現多重繼承?

多重繼承是物件導向概念的一項特徵,其中一個類別可以從多個父類別繼承屬性。當超類別和子類別中存在具有相同簽名的方法時,就會出現問題。當呼叫方法時,編譯器無法確定應該呼叫哪個類別方法,甚至在呼叫優先的類別方法時也是如此。因此,Java不支援多重繼承!但是有一種漏洞,我們接下來會講到。正如我之前提到的,隨著 Java 8 的發布,介面中加入了擁有預設方法的功能。如果實作介面的類別沒有重寫這個方法,那麼就會使用這個預設實作(沒有必要重寫預設方法,例如實作一個抽象方法)。在這種情況下,可以在一個類別中實作不同的介面並使用它們的預設方法。讓我們來看一個例子。我們有一些傳單介面,帶有預設的Fly()方法:
public interface Flyer {
 default void fly() {
   System.out.println("Я лечу!!!");
 }
}
walker 接口,具有預設的walk()方法:
public interface Walker {
 default void walk() {
   System.out.println("Я хожу!!!");
 }
}
Swimmer 接口,附Swim()方法:
public interface Swimmer {
 default void swim() {
   System.out.println("Я плыву!!!");
 }
}
好吧,現在讓我們在一個鴨子類別中實現所有這些:
public class Duck implements Flyer, Swimmer, Walker {
}
讓我們運行鴨子的所有方法:
Duck donald = new Duck();
donald.walk();
donald.fly();
donald.swim();
在控制台中我們將收到:
我去!!!我在飛!!!我在游泳!!!
這意味著我們已經正確地描述了多重繼承,儘管事實並非如此。 Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 14 - 8我還要注意的是,如果一個類別實現的介面的預設方法具有相同的方法名稱和相同的參數,那麼編譯器將開始抱怨不相容性,因為它不明白真正需要使用哪個方法。有幾種出路:
  • 重新命名介面中的方法,使它們彼此不同。
  • 在實作類別中重寫此類有爭議的方法。
  • 從實現這些有爭議的方法的類別繼承(然後您的類別將準確地使用其實作)。

8.final、finally 和 Finalize() 方法之間有什麼不同?

Final是一個關鍵字,用來對類別、方法或變數進行約束,約束的意思是:
  • 對於變數 - 初始初始化後,不能重新定義該變數。
  • 對於方法來說,該方法不能在子類別(繼承類別)中被重寫。
  • 對於一個類別-該類別不能被繼承。
finally是程式碼區塊之前的關鍵字,在處理例外狀況時與try區塊結合使用,並與 catch 區塊一起使用(或可互換)。無論是否拋出異常,該區塊中的程式碼在任何情況下都會執行。在本文的這一部分中,在問題 104 中,討論了該區塊不會被執行的特殊情況。 Finalize()是Object類別的一個方法,在每個物件被垃圾收集器刪除之前調用,該方法會被調用(最後),用於清理佔用的資源。有關每個物件繼承的Object類別的方法的更多信息,請參閱本文這部分中的問題 11 。好了,今天我們就到此結束。下一部分見! Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 14 - 9
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION