CodeGym /Java Blog /Toto sisi /探索 Java 開發人員職位面試中的問題和答案。第 4 部分
John Squirrels
等級 41
San Francisco

探索 Java 開發人員職位面試中的問題和答案。第 4 部分

在 Toto sisi 群組發布
大家好!今天我繼續回顧 Java 開發者面試問題。 探索 Java 開發人員職位面試中的問題和答案。 第 4 - 1 部分

29. return 可以在建構函式中使用嗎?

是的,但只有return關鍵字右邊沒有值。您可以使用返回;作為建構函式中的輔助語句,用於緊急終止(中斷)進一步程式碼的執行並完成物件的初始化。例如,假設我們有一個Cat類,如果一隻Cat無家可歸(isHomeless = true,那麼我們想要終止初始化並且不填寫其他字段(畢竟,它們對我們來說是未知的,因為貓無家可歸歸) :
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
但如果我們談論的是具體值,那麼return關鍵字就不能回傳特定值,因為:
  • 當你聲明一個建構函數時,你不會有像返回類型這樣的東西;
  • 通常,建構函數在實例化期間會隱式地呼叫;
  • 建構子不是方法:它是一個單獨的機制,其唯一目的是初始化實例變量,也就是我們使用 new運算子來建立物件。
探索 Java 開發人員職位面試中的問題和答案。 第 4 - 2 部分

30. 建構函數可以拋出異常嗎?

構造函數處理異常的方式與方法相同。方法允許我們透過在方法頭中寫入throws <ExceptionType>來拋出異常。建構函數允許我們做同樣的事情。當我們繼承並定義子類別的建構子時,我們可以擴大異常類型 - 例如,IOException -> Exception(但反之則不然)。讓我們使用Cat類別的建構子作為建構子拋出異常的範例。假設當我們建立一個物件時,我們想要從控制台輸入名稱和年齡:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
由於reader.readLine()拋出 IOException,我們將其作為可能拋出的例外寫入標頭中。

31. 類別頭的元素是什麼?寫一個例子

為了說明構成類別頭的元素,讓我們來看一個小模式:
  • 強制元素出現在括號 <> 中
  • 可選元素位於 {} 中
{存取修飾符}{靜態}{final}{抽象}<類別名稱>{父類別的繼承}{介面的實作}所以,我們有:{存取修飾符} - 只有公共預設存取修飾符用於班級。 {static}static修飾符表示該類別是靜態的;它僅適用於內部類別(其他類別中的類別)。 {final} — 當然,這是最終修飾符,它使類別不可繼承(開箱即用的範例是String)。 {abstract}抽象修飾符,表示該類別可能具有未實作的方法。此修飾符與最終修飾符衝突。類別頭只能有其中之一,因為abstract修飾符意味著該類別將被繼承並且其抽像元素將被實現。但final表示這是該類別的最終版本,並且不能被繼承。實際上,同時使用這兩個修飾符是荒謬的。編譯器不會讓我們這麼做。 <class>是一個強制關鍵字,表示類別聲明。 <class name>是一個簡單的類別名,它成為特定 Java 類別的識別碼。完全限定的類別名稱由限定的套件名稱加上“.”組成。加上簡單的類別名稱。 {父類別的繼承}是使用extends關鍵字指示父類別(如果有)。例如,...擴充 ParentClass{介面的實作} — 此類別使用implements關鍵字實作的介面清單(如果有)。例如: ...實作 FirstInterface、SecondInterface ... 作為範例,請考慮Lion類別的類別標題,該類別繼承Cat並實作WildAnimal介面:
public final class Lion extends Cat implements WildAnimal
探索 Java 開發人員職位面試中的問題和答案。 第 4 - 3 部分

32. 方法頭的元素是什麼?寫一個例子

在考慮構成方法頭的元素時,讓我們再次考慮一個小模式:
  • 強制元素出現在括號 <> 中
  • 可選元素位於 {} 中
{存取修飾符}{static}{abstract}{final}{synchronized} {native} <返回值><方法名稱> <(>{方法參數}<}>{拋出異常} {存取修飾符} — 所有存取 修飾符都是可用於方法 — publicprotecteddefaultprivate{static}static修飾符,表示該方法是靜態的,因此與類別相關聯,而不是物件。 {abstract}抽象修飾符,表示方法沒有實現(主體)。為了正確工作,宣告該方法的類別也必須具有abstract修飾符。如在類別頭中,該修飾符與final修飾符衝突,也與static修飾符衝突,因為抽象方法意味著重寫後代中方法,靜態 方法不能被 重寫。從不同的線程同時存取它。如果該方法不是靜態的,則該方法對於物件的 this 互斥鎖是關閉的。如果該方法是靜態的,那麼它對於當前類別的互斥鎖是關閉的。 {native}native修飾符指示方法是用另一種程式語言編寫的。 <return type> — 方法必須傳回的值的類型。如果該方法不傳回任何內容,則傳回 void<方法名稱> ——方法名稱的名稱,也就是它在系統中的識別碼。 {方法參數} — 方法接受的參數:它們是實現其功能所必需的。 {拋出的例外}拋出 <ExceptionType> — 此方法可以拋出的已檢查例外狀況的清單。我將提供以下內容作為方法標頭的範例:
public static void main(String[] args) throws IOException

33. 如果基底類別中尚未定義預設建構函數(但定義了不同的建構子),則在子類別中建立預設建構函數

我不確定我完全理解這個問題,但這也許意味著我們在父類別中有一些像這樣的建構子:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
在這種情況下,在父類別中,我們肯定需要定義一個建構函式來初始化父類別(即呼叫父建構子):
public class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
探索 Java 開發人員職位面試中的問題和答案。 第 4 - 4 部分

34.什麼時候使用this關鍵字?

在 Java 中,有兩種不同的意義。1. 它是對目前物件的引用,例如this.age = 9。也就是說,this指的是使用它的物件以及帶有this 的程式碼所指的物件。主要目的是提高程式碼可讀性並避免歧義。例如,如果實例欄位和方法參數具有相同的名稱:
public void setName(String name) {
   this.name = name;
}
也就是說,this.name是物件的字段,而name是方法參數。this引用不能在靜態方法中使用。2. 在建構子中,this可以像方法一樣被調用,例如this(value)。在這種情況下,它將呼叫同一類別的另一個建構函數。基本上,您可以在建立物件的過程中呼叫兩個建構函式:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
當呼叫第一個建構函式建立Cat物件時,兩個實例欄位都會成功初始化。這裡有一些細微差別:
  1. this()僅適用於建構子。
  2. 對另一個建構函式的參考必須位於建構函式區塊(主體)的第一行。這意味著構造函數不能呼叫其類別的多個(其他)構造函數。
探索 Java 開發人員職位面試中的問題和答案。 第 4 - 5 部分

35.什麼是初始化器?

據我了解,這個問題是關於普通和靜態初始化塊的。讓我們先記住什麼是初始化。初始化是字段的創建、激活、準備和定義。準備程序或組件以供使用。你會記得,當你建立一個物件時,類別變數可以在宣告時立即初始化:
class Cat {
   private int age = 9;
   private String name = "Tom";
或透過構造函數事後設定:
class Cat {
   private int age;
   private String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
但還有另一種方法:您可以使用初始化區塊設定實例變量,該初始化區塊在類別中 採用大括號{} 的形式,沒有名稱(如無名方法或建構子):
class Cat {
   private int age;
   private String name;

   {
       age = 10;
       name = "Tom";
   }
初始化區塊是創建物件時載入的一段程式碼。此類區塊通常用於執行載入類別時所需的某些複雜計算。這些計算的結果可以設定為變數的值。除了普通的初始化塊之外,還有靜態的初始化塊。它們看起來相同,但在左大括號前面 有static關鍵字:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
此塊與前一個塊相同。但是,如果普通物件在初始化每個物件時執行,則靜態物件僅在類別載入時執行一次。通常,某些複雜的計算是在靜態區塊中執行的,用於初始化靜態類別變數。同樣的限制也適用於靜態方法的靜態區塊:不能使用非靜態數據,例如靜態區塊中 對目前物件 ( this ) 的引用。探索 Java 開發人員職位面試中的問題和答案。 第 4 - 6 部分現在我們可以查看類別(及其父類別)的初始化順序,以便更好地理解何時調用初始化區塊。

36.給定一個擴展Parent的公共Child類,寫出該物件的初始化順序

當載入Child類別時,初始化順序如下:
  1. 類別的靜態類別欄位。
  2. 類別的靜態初始化塊。
  3. Сchild類別的靜態欄位。
  4. Child類別的靜態初始化區塊。
  5. 類別的非靜態欄位。
  6. 類別的非靜態初始化塊。
  7. 類別建構函數。
  8. Сhild類別的非靜態字段。
  9. Сhild類別的非靜態初始化塊。
  10. Сchild類別的建構子。
探索 Java 開發人員職位面試中的問題和答案。 第 4 - 7 部分

37.你知道類別(物件)之間有哪些關係?

Java 中有兩種變數:原始型別和對成熟物件的參考。
  • IS-A關係
OOP 的 IS-A 原則是基於類別繼承或介面實作。例如,如果Lion類別繼承Cat,那麼我們說LionCat
Lion IS-A Cat
(但不是每隻貓都是獅子)介面也存在同樣的情況。如果Lion類別實作了WildAnimal接口,那麼它們也存在關係:
Lion IS-A WildAnimal
  • HAS-A關係
這種類型的關係是一個類別使用其他類別的關係,也稱為「關聯」。關聯是一個類別引用另一個類別(或相互引用)。例如,Car類可以引用Passenger類,這將構成以下關係:
Car HAS-A Passenger
反之亦然:如果Passenger引用了Car,那麼關係如下:
Passenger HAS-A Car

38.你知道哪些關聯對象關係?

聚合和組合只不過是關聯的特殊情況。 聚合是一種關係,其中一個物件是另一個物件的一部分。例如,乘客可能位於汽車內。更重要的是,可能有多名乘客,或者根本沒有乘客(如果我們談論的是特斯拉,可能沒有司機)。例如:
public class Car {
   private List passengers = new ArrayList<>();

 void setPassenger(Passenger passenger) {
     passengers.add(passenger);
 }

   void move() {
       for (Passenger passenger : passengers) {
           System.out.println("Transporting passenger - " + passenger.toString());
       }
       passengers.clear();
   }
}
換句話說,乘客數量(任何數量)對我們來說並不重要:Car類的功能不依賴於此。聚合也意味著當另一個物件使用一個物件時,第一個物件可以被其他物件使用。例如,同一位學生可能同時參加針織俱樂部和搖滾樂隊,並同時參加西班牙語課程。正如你可以想像的,聚合是類別之間更鬆散的關聯關係。 組合是一種更緊密的關係,其中一個物件不僅是另一個物件的一部分,而且一個物件的工作非常依賴另一個物件。例如,汽車有引擎。引擎可以在沒有汽車的情況下存在,但離開汽車就毫無用處。沒有引擎汽車就無法運作:
public class Car {
   private Engine engine;

   public Car(Engine engine) {
       this.engine = engine;
   }

   void startMoving() {
       engine.start();
           ...
   }
組合也意味著當另一個物件使用一個物件時,第一個物件不能屬於任何其他物件。回到我們的例子,一台引擎只能屬於一輛汽車,不能同時屬於兩輛或更多汽車。我想今天的內容就夠了,所以我們就到此為止。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION