JavaRush /Blog Java /Random-VI /Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấ...

Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java. Phần 11

Xuất bản trong nhóm
Xin chào! Ngay cả con tàu nhanh nhất không có lộ trình cũng sẽ trôi theo sóng. Nếu bạn đang đọc bài viết của tôi bây giờ, bạn chắc chắn có một mục tiêu. Điều quan trọng không phải là đi lạc lối mà là đi theo con đường của bạn đến cùng - trở thành nhà phát triển Java. Hôm nay tôi muốn tiếp tục phân tích hơn 250 câu hỏi dành cho các nhà phát triển Java, điều này sẽ giúp bạn giải quyết một số lỗ hổng trong lý thuyết. Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 1

97. Các điều kiện xác định lại thỏa thuận có được áp dụng khi xác định lại Bằng không?

Phương thức bằng() được ghi đè phải tuân thủ các điều kiện (quy tắc) sau:
  • tính phản xạ - đối với bất kỳ giá trị x nào, một biểu thức như x.equals(x) phải luôn trả về true (khi x != null ).

  • tính đối xứng - đối với mọi giá trị của xy, một biểu thức có dạng 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ị của 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ị của xy, lệnh gọi lặp lại tới x.equals(y) sẽ luôn trả về giá trị của lệnh gọi trước đó cho phương thức này, miễn là các trường được sử dụng để so sánh hai đối tượng không thay đổi giữa các lệnh gọi .

  • so sánh null - với bất kỳ giá trị x nào, việc gọi x.equals(null) sẽ trả về false .

98. Điều gì sẽ xảy ra nếu bạn không ghi đè Equals và HashCode?

Trong trường hợp này, hashCode() sẽ trả về một số được tạo dựa trên vị trí bộ nhớ nơi đối tượng đã cho được lưu trữ. Nghĩa là, hai đối tượng có trường giống hệt nhau sẽ nhận được các giá trị khác nhau khi gọi hàm hashCode() không bị ghi đè (xét cho cùng, chúng được lưu trữ ở các vị trí bộ nhớ khác nhau). Bằng() không được ghi đè sẽ so sánh các tham chiếu để xem liệu chúng có trỏ đến cùng một đối tượng hay không. Nghĩa là, việc so sánh được thực hiện thông qua == và trong trường hợp các đối tượng có cùng trường, nó sẽ luôn trả về false . Đúng sẽ chỉ khi so sánh các tham chiếu đến cùng một đối tượng. Đôi khi có logic trong việc không ghi đè các phương thức này. 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 và việc ghi đè các phương thức này sẽ chỉ làm hỏng tính logic của tính duy nhất. Điều chính là hiểu các sắc thái của các phương pháp bị ghi đè và không bị ghi đè và sử dụng cả hai phương pháp tùy theo tình huống.

99. Tại sao tính đối xứng chỉ đúng nếu x.equals(y) trả về true?

Một câu hỏi 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à logic đơn giản. Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 2

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

Xung đột hashCode là tình huống trong đó hai đối tượng khác nhau có cùng giá trị hashCode . Sao có thể như thế được? Thực tế là mã băm được ánh xạ tới loại Số nguyên , loại này có phạm vi từ -2147483648 đến 2147483647, tức là khoảng 4 tỷ số nguyên khác nhau. Phạm vi này rất lớn, tuy nhiên, nó không phải là vô hạn. Do đó, có thể xảy ra trường hợp hai đối tượng hoàn toàn khác nhau có cùng mã băm. Điều này rất khó xảy ra, nhưng có thể. Hàm băm được triển khai kém cũng có thể làm tăng tần suất của các mã băm giống hệt nhau, chẳng hạn như sẽ trả về các số trong phạm vi nhỏ, điều này sẽ làm tăng khả năng xảy ra xung đột. Để chống xung đột, bạn cần triển khai tốt phương thức hashCode để mức độ lan truyền của các giá trị là tối đa và cơ hội lặp lại các giá trị là tối thiểu.

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

Nếu một phần tử liên quan đến việc tính toán mã băm bị thay đổi thì mã băm của chính đối tượng đó cũng sẽ bị thay đổi (nếu hàm băm tốt). Do đó, trong HashMap , nên sử dụng các đối tượng bất biến (không thể thay đổi) làm khóa, vì trạng thái (trường) bên trong của chúng không thể thay đổi sau khi tạo. Theo đó, hash code của họ cũng không được chuyển đổ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 bạn thay đổi các trường của đối tượng này, mã băm của nó sẽ thay đổi và kết quả là bạn có thể mất cặp này trong HashMap . Sau cùng, nó sẽ được lưu trữ trong nhóm dành cho mã băm ban đầu và sau khi thay đổi nó sẽ được tìm kiếm trong một nhóm khác. Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 3

102. Viết các phương thức Equals và HashCode cho lớp Sinh viên, bao gồm 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 trực tiếp các liên kết, bởi vì nếu các liên kết đến cùng một đối tượng thì việc tiếp tục kiểm tra có ích lợi gì? Dù thế nào đi nữa mọi thứ sẽ là sự thật .

  • Kiểm tra null và các loại lớp phù hợp, bởi vì nếu một đối tượng là đối số của null hoặc loại khác, điều này có nghĩa là các đối tượng không bằng nhau - false .

  • Truyền đối tượng đối số thành một loại (trong trường hợp đó là đối tượng của loại cha).

  • So sánh trường lớp nguyên thủy (xét cho cùng, so sánh qua =! là đủ cho nó ), nếu trường không bằng - false .

  • Kiểm tra trường không nguyên thủy để tìm null và bằng (trong Chuỗi phương thức được ghi đè và sẽ so sánh chính xác), nếu cả hai trường đều là null hoặc bằng thì quá trình kiểm tra kết thúc và phương thức trả về true .

Mã Băm:
  • Đặt giá trị mã băm ban đầu thành giá trị nguyên thủy của đối tượng .

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

  • Trả về kết quả.

  • Kết quả của việc ghi đè mã băm này là các đối tượng có cùng tên và giá trị int sẽ luôn trả về cùng một giá trị.

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 cách tiếp cận làm gì:
  • instanceof kiểm tra xem một tham chiếu đối tượng ở phía bên trái có phải là một thể hiện của một kiểu ở phía bên phải hay một kiểu con nào đó của nó hay không.

  • getClass() == ... kiểm tra danh tính loại.

Nghĩa là, nếu getClass() kiểm tra danh tính đầy đủ của một lớp thì instanceof sẽ 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 chủ động sử dụng tính đa hình. Trên thực tế, cả hai cách tiếp cận đều tốt nếu bạn hiểu đặc điểm công việc của chú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().

Clone() là một phương thức của lớp Object , mục đích của nó là tạo và trả về một bản sao của đối tượng hiện tại (một bản sao của đối tượng hiện tại). Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 4Để sử dụng nó, 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();
}
Xét cho cùng, trong lớp Đối tượng , nó được bảo vệ, nghĩa là nó sẽ chỉ hiển thị trong chính lớp Sinh viên , nhưng không hiển thị với các lớp từ bên ngoài.

105. Điểm đặc biệt của phương thức clone() khi làm việc với các trường của đối tượng thuộc kiểu tham chiếu là gì?

Khi nhân bản các đối tượng, chỉ các giá trị nguyên thủy và giá trị của 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ó một liên kết đến một đối tượng khác trong trường bên trong của nó thì chỉ liên kết này sẽ được sao chép, nhưng bản thân đối tượng kia sẽ không được sao chép. Trên thực tế, đây là cái mà họ gọi là nhân bản bề mặt. Chà, điều gì sẽ xảy ra nếu bạn cần nhân bản chính thức bằng cách nhân bản tất cả các đối tượng lồng nhau? Làm thế nào để đảm bảo rằng đây không phải là bản sao của các liên kết mà là bản sao chính thức của các đối tượng với các ô nhớ bị chiếm dụng khác trong heap? Trên thực tế, mọi thứ khá đơn giản - để làm được điều này, bạn cũng cần ghi đè phương thức clone() trong mỗi lớp của các đối tượng bên trong này và thêm giao diện điểm đánh dấu - Cloneable . Khi đó, nó sẽ không phải là các tham chiếu đến các đối tượng sẽ được sao chép mà là chính các đối tượng đó, bởi vì giờ đây chúng cũng có khả năng tự sao chép.

Ngoại lệ

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

Cả ngoại lệ và lỗi đều là lớp con của lớp 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 không đủ tài nguyên hệ thống. Và ứng dụng của chúng tôi sẽ không phát hiện ra những loại vấn đề này. Một số ví dụ về lỗi là lỗi 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 thuộc loại không được kiểm tra. Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 5Ngoạ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. Thông thường điều này xảy ra trong mã được viết bởi các nhà phát triển. Nghĩa là, các trường hợp ngoại lệ dễ dự đoán hơn và phụ thuộc nhiều hơn vào chúng tôi với tư cách là nhà phát triển. Đồng thời, các lỗi xảy ra ngẫu nhiên hơn và độc lập hơn với chúng ta mà phụ thuộc vào các vấn đề với chính hệ thống nơi ứng dụng của chúng ta chạy.

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

Như tôi đã nói trước đó, một ngoại lệ là một lỗi trong quá trình thực thi chương trình và trong quá trình 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à một loại ngoại lệ phải luôn được xử lý bằng cơ chế thử bắt hoặc được đưa vào các phương thức trên. Các lần ném được sử dụng trong tiêu đề phương thức để chỉ ra các trường hợp ngoại lệ có thể xảy ra do phương thức đó đưa ra. Tức là đây là cơ chế “ném” ngoại lệ vào các phương thức trên. Không được kiểm tra là một loại ngoại lệ không cần phải xử lý và thường khó dự đoán hơn cũng như ít có khả năng xảy ra hơn. Tuy nhiên, chúng cũng có thể được xử lý nếu muốn. Throw được sử dụng khi ném một ngoại lệ theo cách thủ công, ví dụ:
throw new Exception();

108. Thứ bậc của các ngoại lệ là gì?

Hệ thống phân cấp của các trường hợp ngoại lệ rất lớn và rộng, thậm chí quá rộng để có thể kể hết mọi thứ về nó ở đây. Do đó, chúng ta sẽ chỉ xem xét các liên kết chính của nó: Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 6Ở đây, ở trên cùng của hệ thống phân cấp, chúng ta thấy lớp - Throwable - một lớp chung, tổ tiên của hệ thống phân cấp ngoại lệ, lần lượt được chia thành:
  • Lỗi - lỗi nghiêm trọng, không thể kiểm tra được.
  • Ngoại lệ - ngoại lệ được kiểm tra.
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:
  • Đã kiểm tra - các ngoại lệ mà bạn phải xử lý bằng cách nào đó, nghĩa là xử lý chúng trong khối try - Catch hoặc "chuyển tiếp" chúng sang phương thức trên. Để thực hiện điều này, trong chữ ký phương thức, sau khi liệt kê các đối số của phương thức, bạn cần sử dụng từ khóa trows <Exception type> , để cho người dùng phương thức biết rằng phương thức có thể đưa ra ngoại lệ này (giống như một cảnh báo) và chuyển trách nhiệm xử lý ngoại lệ cho người dùng phương pháp này.

  • Không được kiểm tra - các ngoại lệ không cần phải xử lý vì chúng không được kiểm tra tại thời điểm biên dịch và theo quy luật, khó dự đoán hơn. Đó là, sự khác biệt chính với đã kiểm tra là đối với chúng, các cơ chế thử bắt hoặc ném này hoạt động giống nhau, nhưng chúng không bắt buộc.

101. Viết ví dụ về việc chặn và xử lý một ngoại lệ trong khối try-catch của một phương thức

try{                                                 // начало блока перехвата
 throw new Exception();                             // ручной бросок исключения
} catch (Exception e) {                              // данное исключение и его потомки будут перехватываться
 System.out.println("Упс, что-то пошло не так =("); // вывод некоторого исключения в консоль
}

102. Viết ví dụ về cách bắt và xử lý một ngoại lệ bằng ngoại lệ của riêng bạn

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

 public CustomException(final String message) {
   super(message);
 }
}
Chà, sau đó chúng ta sẽ ném nó theo cách thủ công và chặn nó như trong câu hỏi trước:
try{
 throw new CustomException("Упс, что-то пошло не так =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
Và một lần nữa, khi bạn chạy nó, bạn sẽ nhận được kết quả đầu ra sau trên bàn điều khiển:
Rất tiếc, có gì đó không ổn =(
Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 11 - 7Bạn có thể tìm hiểu thêm về các trường hợp ngoại lệ ở đây . Vâ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!
Các tài liệu khác trong loạt bài:
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION