CodeGym /Blog Java /Ngẫu nhiên /Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin...
John Squirrels
Mức độ
San Francisco

Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java. Phần 11

Xuất bản trong nhóm
CHÀO! Ngay cả con tàu nhanh nhất cũng sẽ trôi dạt trên sóng nếu nó không có lộ trình. Nếu bạn đang đọc bài viết này ngay bây giờ, bạn chắc chắn có một mục tiêu. Điều quan trọng là không đi chệch hướng mà thay vào đó hãy nỗ lực hết mình để trở thành một nhà phát triển Java. Hôm nay tôi muốn tiếp tục xem xét các câu hỏi dành cho các nhà phát triển Java để giúp lấp đầy một số lỗ hổng về mặt lý thuyết của bạn. Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java.  Phần 11 - 1

97. Có áp dụng quy tắc nào khi ghi đè bằng() không?

Khi ghi đè phương thức bằng(), bạn phải tuân thủ các quy tắc sau:
  • tính phản xạ - đối với mọi giá trị x , x.equals(x) phải luôn trả về true (trong đó x != null ).

  • tính đối xứng - đối với mọi giá trị xy , x.equals(y) chỉ phải trả về true nếu y.equals(x) trả về true .

  • tính bắc cầu - đối với mọi giá trị x , yz , nếu x.equals(y) trả về truey.equals(z) cũng trả về true , thì x.equals(z) phải trả về true .

  • tính nhất quán - đối với mọi giá trị xy , việc gọi x.equals(y) liên tục sẽ luôn trả về cùng một giá trị miễn là các trường được sử dụng để so sánh hai đối tượng không thay đổi giữa mỗi lần gọi.

  • so sánh null - đối với mọi giá trị x , việc gọi x.equals(null) phải trả về false .

98. Điều gì xảy ra nếu bạn không ghi đè bằng() và hashCode()?

Trong trường hợp này, hashCode() sẽ trả về một số được tạo dựa trên địa chỉ của ô nhớ nơi đối tượng được lưu trữ. Nói cách khác, khi phương thức hashCode() ban đầu được gọi trên hai đối tượng có các trường giống hệt nhau, kết quả sẽ khác nhau (vì chúng được lưu trữ ở các vị trí bộ nhớ khác nhau). Phương thức Equals() ban đầu so sánh các tham chiếu, tức là nó cho biết liệu các tham chiếu có trỏ đến cùng một đối tượng hay không. Nói cách khác, phép so sánh sử dụng toán tử == và nó sẽ luôn trả về false cho các đối tượng khác nhau, ngay cả khi các trường của chúng giống hệt nhau. true chỉ được trả về khi so sánh các tham chiếu đến cùng một đối tượng. Đôi khi việc không ghi đè các phương thức này là điều hợp lý. Ví dụ: bạn muốn tất cả các đối tượng của một lớp nhất định là duy nhất - việc ghi đè các phương thức này chỉ có thể làm hỏng sự đảm bảo hiện có về mã băm duy nhất. Điều quan trọng là phải hiểu các sắc thái của các phương pháp này, cho dù có ghi đè hay không, và sử dụng bất kỳ cách tiếp cận nào mà tình huống yêu cầu.

99. Tại sao yêu cầu về tính đối xứng chỉ được thỏa mãn nếu x.equals(y) trả về true?

Câu hỏi này hơi lạ. Nếu vật A bằng vật B thì vật B bằng vật A. Nếu B không bằng vật A thì làm sao điều ngược lại có thể xảy ra? Đây là lẽ thường.

100. Xung đột HashCode là gì? Làm thế nào để bạn đối phó với nó?

Xung đột HashCode xảy ra khi hai đối tượng khác nhau có cùng HashCode . Làm sao điều đó có thể được? Chà, mã băm được ánh xạ tới một Số nguyên, có phạm vi từ -2147483648 đến 2147483647. Nghĩa là, nó có thể là một trong khoảng 4 tỷ số nguyên khác nhau. Phạm vi này rất lớn nhưng không phải là vô hạn. Điều đó có nghĩa là có những trường hợp hai đối tượng hoàn toàn khác nhau có thể có cùng mã băm. Nó rất khó xảy ra, nhưng nó có thể. Hàm băm được triển khai kém có thể tạo ra các mã băm giống hệt nhau thường xuyên hơn bằng cách trả về các số trong phạm vi nhỏ, do đó làm tăng khả năng xung đột. Để giảm xung đột, bạn cần triển khai tốt phương pháp HashCode để trải đều các giá trị và giảm thiểu khả năng lặp lại các giá trị.

101. Điều gì xảy ra nếu giá trị của một phần tử tham gia hợp đồng hashCode thay đổi?

Nếu một phần tử liên quan đến việc tính toán mã băm thay đổi thì mã băm của đối tượng sẽ thay đổi (nếu hàm băm tốt). Đó là lý do tại sao bạn nên sử dụng các đối tượng bất biến làm khóa trong HashMap , vì trạng thái (trường) bên trong của chúng không thể thay đổi sau khi tạo. Và theo đó mã băm của họ sẽ thay đổi sau khi tạo. Nếu bạn sử dụng một đối tượng có thể thay đổi làm khóa thì khi các trường của đối tượng thay đổi, mã băm của đối tượng đó sẽ thay đổi và bạn có thể mất cặp khóa-giá trị tương ứng trong HashMap . Cuối cùng, nó sẽ được lưu trữ trong nhóm được liên kết với mã băm ban đầu, nhưng sau khi đối tượng thay đổi, bạn sẽ tìm kiếm nó trong một nhóm khác.

102. Viết các phương thức Equals() và hashCode() cho lớp Sinh viên có các trường String name và int age.

public class Student {
int age;
String name;

 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }

   final Student student = (Student) o;

   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
bằng():
  • Đầu tiên, chúng ta so sánh các tham chiếu một cách trực tiếp, bởi vì nếu các tham chiếu trỏ đến cùng một đối tượng thì việc tiếp tục kiểm tra sự bằng nhau có ý nghĩa gì? Chúng tôi đã biết rằng kết quả sẽ là sự thật .

  • Chúng tôi kiểm tra null và xem các loại lớp có giống nhau hay không vì nếu tham số là null hoặc thuộc loại khác thì các đối tượng không thể bằng nhau và kết quả phải là false .

  • Chúng ta chuyển tham số thành cùng một loại (xét cho cùng, nếu nó là một đối tượng của kiểu cha thì sao).

  • Chúng tôi so sánh các trường nguyên thủy (so sánh bằng cách sử dụng =! sẽ đủ). Nếu chúng không bằng nhau, chúng ta trả về false .

  • Chúng tôi kiểm tra trường không nguyên thủy để xem liệu nó có rỗng hay không và sử dụng phương thức bằng ( lớp String ghi đè phương thức nên nó sẽ thực hiện so sánh chính xác). Nếu cả hai trường đều rỗng hoặc bằng trả về true , chúng tôi sẽ ngừng kiểm tra và phương thức trả về true .

Mã Băm() :
  • Chúng tôi đặt giá trị ban đầu của mã băm bằng giá trị của trường tuổi của đối tượng .

  • Chúng tôi nhân mã băm hiện tại với 31 (để có mức chênh lệch giá trị lớn hơn) rồi thêm mã băm của trường Chuỗi không nguyên thủy (nếu nó không rỗng).

  • Chúng tôi trả lại kết quả.

  • Ghi đè phương thức theo cách này có nghĩa là các đối tượng có cùng tên và giá trị int sẽ luôn trả về cùng một mã băm.

103. Sự khác biệt giữa việc sử dụng "if (obj instanceof Sinh viên)" và "if (getClass() == obj.getClass())" là gì?

Chúng ta hãy xem mỗi biểu thức làm gì:
  • instanceof kiểm tra xem tham chiếu đối tượng ở phía bên trái là một thể hiện của loại ở phía bên phải hay một trong các kiểu con của nó.

  • "getClass() == ..." kiểm tra xem các loại có giống nhau không.

Nói cách khác, getClass() trả về danh tính cụ thể của lớp, nhưng instanceof trả về true ngay cả khi đối tượng chỉ là một kiểu con, điều này có thể giúp chúng ta linh hoạt hơn khi sử dụng tính đa hình. Cả hai cách tiếp cận đều đầy hứa hẹn nếu bạn hiểu chính xác cách chúng hoạt động và áp dụng chúng vào đúng chỗ.

104. Hãy mô tả ngắn gọn về phương thức clone().

Phương thức clone () thuộc lớp Object . Mục đích của nó là tạo và trả về một bản sao (bản sao) của đối tượng hiện tại. Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java.  Phần 11 - 2Để sử dụng phương pháp này, bạn cần triển khai giao diện điểm đánh dấu Cloneable :
Student implements Cloneable
Và ghi đè chính phương thức clone() :
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
Suy cho cùng, nó được bảo vệ trong lớp Object , tức là nó sẽ chỉ hiển thị trong lớp Sinh viên và không hiển thị với các lớp bên ngoài.

105. Bạn cần lưu ý điều gì đặc biệt về phương thức clone() và các biến tham chiếu trong một đối tượng?

Khi các đối tượng được sao chép, chỉ các giá trị nguyên thủy và giá trị của các tham chiếu đối tượng được sao chép. Điều này có nghĩa là nếu một đối tượng có trường tham chiếu đến đối tượng khác thì chỉ tham chiếu sẽ được sao chép - đối tượng được tham chiếu khác này sẽ không được sao chép. Đây là những gì được gọi là một bản sao nông. Vì vậy, điều gì sẽ xảy ra nếu bạn cần một bản sao chính thức, trong đó mọi đối tượng lồng nhau đều được sao chép? Làm thế nào để bạn chắc chắn rằng đây không phải là bản sao đơn thuần của các tham chiếu mà thay vào đó là bản sao chính thức của các đối tượng riêng biệt chiếm các địa chỉ bộ nhớ riêng biệt trong vùng heap? Trên thực tế, tất cả đều khá đơn giản — đối với mỗi lớp được tham chiếu nội bộ, bạn cần ghi đè phương thức clone() và thêm giao diện điểm đánh dấu Cloneable . Khi bạn thực hiện việc này, thao tác sao chép sẽ không sao chép các tham chiếu đến các đối tượng hiện có mà thay vào đó sẽ sao chép các đối tượng được tham chiếu, vì giờ đây chúng cũng có khả năng sao chép chính chúng.

Ngoại lệ

106. Sự khác biệt giữa lỗi và ngoại lệ là gì?

Các ngoại lệ cũng như lỗi đều là các lớp con của Throwable . Tuy nhiên, họ có sự khác biệt của họ. Lỗi cho biết sự cố chủ yếu xảy ra do thiếu tài nguyên hệ thống. Và ứng dụng của chúng tôi sẽ không gặp phải những loại sự cố này. Ví dụ về các lỗi này bao gồm sự cố hệ thống và lỗi hết bộ nhớ. Lỗi chủ yếu xảy ra trong thời gian chạy vì chúng không được kiểm tra. Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java.  Phần 11 - 3Ngoại lệ là những vấn đề có thể xảy ra trong thời gian chạy và lúc biên dịch. Những vấn đề này thường phát sinh trong mã mà chúng tôi viết với tư cách là nhà phát triển. Điều đó có nghĩa là những trường hợp ngoại lệ này dễ dự đoán hơn và phụ thuộc nhiều hơn vào chúng ta. Ngược lại, lỗi xảy ra ngẫu nhiên hơn và độc lập hơn với chúng ta. Thay vào đó, chúng phụ thuộc vào các vấn đề trong hệ thống mà ứng dụng của chúng tôi đang chạy.

107. Sự khác biệt giữa được kiểm tra, không được kiểm tra, ngoại lệ, ném và ném là gì?

Như tôi đã nói trước đó, một ngoại lệ là lỗi thời gian chạy hoặc lỗi thời gian biên dịch xảy ra trong mã do nhà phát triển viết (do một số tình huống bất thường). Đã kiểm tra là những gì chúng tôi gọi là ngoại lệ mà một phương thức phải luôn xử lý bằng cách sử dụng cơ chế thử bắt hoặc thử lại phương thức gọi. Từ khóa ném được sử dụng trong tiêu đề phương thức để chỉ ra các ngoại lệ mà phương thức đó có thể đưa ra. Nói cách khác, nó cung cấp cho chúng ta cơ chế ném ngoại lệ vào phương thức gọi. Các trường hợp ngoại lệ không được kiểm tra không cần phải được xử lý. Chúng có xu hướng khó dự đoán hơn và ít có khả năng xảy ra hơn. Điều đó nói rằng, bạn có thể xử lý chúng nếu bạn muốn. Chúng tôi sử dụng Throw khi ném một ngoại lệ theo cách thủ công, ví dụ:
throw new Exception();

108. Hệ thống phân cấp ngoại lệ là gì?

Hệ thống phân cấp ngoại lệ rất rộng rãi. Có quá nhiều thứ để mô tả đầy đủ ở đây. Vì vậy, thay vào đó, chúng ta sẽ chỉ xem xét các nhánh chính của nó: Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java.  Phần 11 - 4 Ở đây, ở trên cùng của hệ thống phân cấp, chúng ta thấy lớp Throwable , là tổ tiên chung của hệ thống phân cấp ngoại lệ và lần lượt được chia thành:
  • Lỗi - vấn đề nghiêm trọng, không được kiểm tra.
  • Ngoại lệ - ngoại lệ có thể được kiểm tra.
Các ngoại lệ được chia thành các ngoại lệ thời gian chạy không được kiểm tra khác nhau và các ngoại lệ được kiểm tra khác nhau.

109. Ngoại lệ được kiểm tra và không được kiểm tra là gì?

Như tôi đã nói trước đây:
  • Các ngoại lệ được kiểm tra là những ngoại lệ mà bạn phải xử lý bằng cách nào đó. Nghĩa là, bạn phải xử lý chúng trong khối try-catch hoặc ném chúng vào phương thức trên. Để thực hiện việc này, sau khi liệt kê các đối số của phương thức trong chữ ký phương thức, hãy sử dụng Throws <loại ngoại lệ> để chỉ ra rằng phương thức đó có thể ném ngoại lệ đó. Điều này giống như một lời cảnh báo, nhắc nhở phương thức gọi rằng nó phải chịu trách nhiệm xử lý ngoại lệ đó.

  • Các trường hợp ngoại lệ không được kiểm tra không cần phải được xử lý vì chúng không được kiểm tra tại thời điểm biên dịch và thường khó dự đoán hơn. Sự khác biệt chính của chúng với các ngoại lệ được kiểm tra là việc xử lý chúng bằng cách sử dụng khối thử bắt hoặc bằng cách thử lại là tùy chọn thay vì bắt buộc.

101. Viết một ví dụ trong đó bạn sử dụng khối try-catch để bắt và xử lý một ngoại lệ.

try{                                                 // Start of the try-catch block
 throw new Exception();                             // Manually throw an exception
} catch (Exception e) {                              // Exceptions of this type and its subtypes will be caught
 System.out.println("Oops! Something went wrong =("); // Display the exception
}

102. Viết một ví dụ trong đó bạn nắm bắt và xử lý các ngoại lệ tùy chỉnh của riêng mình.

Trước tiên, hãy viết lớp ngoại lệ của riêng chúng ta kế thừa Ngoại lệ và ghi đè hàm tạo của nó lấy thông báo lỗi làm đối số:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
Tiếp theo, chúng ta sẽ ném một con theo cách thủ công và bắt nó giống như chúng ta đã làm trong ví dụ cho câu hỏi trước:
try{
 throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
Một lần nữa, khi chạy mã, chúng tôi nhận được kết quả đầu ra sau:
Ối! Có gì đó không ổn =(
Khám phá các câu hỏi và câu trả lời từ cuộc phỏng vấn xin việc cho vị trí nhà phát triển Java.  Phần 11 - 5Vâng, đó là tất cả cho ngày hôm nay! Hẹn gặp lại các bạn ở phần tiếp theo!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION