JavaRush /Blog Java /Random-VI /Lõi Java. Những câu hỏi phỏng vấn phần 3
Vadim625
Mức độ

Lõi Java. Những câu hỏi phỏng vấn phần 3

Xuất bản trong nhóm
Trong hai bài viết trước, chúng tôi đã thảo luận về một số câu hỏi quan trọng mà bạn thường được hỏi nhất trong các cuộc phỏng vấn. Đã đến lúc tiếp tục và xem các câu hỏi còn lại.
Lõi Java.  Câu hỏi phỏng vấn phần 3 - 1

Sao chép sâu và sao chép nông

Một bản sao chính xác của bản gốc là bản sao của nó. Trong Java, điều này có nghĩa là có thể tạo một đối tượng có cấu trúc tương tự như đối tượng ban đầu. Phương pháp này clone()cung cấp chức năng này. Sao chép nông càng ít thông tin càng tốt. Theo mặc định, nhân bản trong Java là nông cạn, tức là Object classkhông biết về cấu trúc của lớp mà nó đang sao chép. Khi nhân bản, JVM thực hiện như sau:
  1. Nếu một lớp chỉ có các thành viên thuộc kiểu nguyên thủy thì một bản sao hoàn toàn mới của đối tượng sẽ được tạo và một tham chiếu đến đối tượng đó sẽ được trả về.
  2. Nếu một lớp không chỉ chứa các thành viên của các kiểu nguyên thủy mà còn chứa các thành viên của bất kỳ kiểu lớp nào khác, thì các tham chiếu đến các đối tượng của các lớp này sẽ được sao chép. Do đó, cả hai đối tượng sẽ có cùng tham chiếu.
Sao chép sâu sao chép mọi thứ. Sao chép sâu là hai bộ sưu tập, một trong số đó sao chép tất cả các thành phần của bộ sưu tập gốc. Chúng tôi muốn tạo một bản sao sao cho việc thay đổi bất kỳ thành phần nào của bản sao sẽ không ảnh hưởng đến bộ sưu tập gốc. Nhân bản sâu yêu cầu các quy tắc sau:
  1. Không cần phải sao chép dữ liệu nguyên thủy một cách riêng biệt;
  2. Tất cả các lớp thành viên trong lớp gốc phải hỗ trợ nhân bản. Đối với mỗi thành viên lớp, phải được gọi super.clone()khi phương thức bị ghi đè clone();
  3. Nếu bất kỳ thành viên nào của một lớp không hỗ trợ nhân bản, thì trong phương thức nhân bản, bạn cần tạo một thể hiện mới của lớp đó và sao chép từng thành viên của nó với tất cả các thuộc tính vào một đối tượng lớp mới, mỗi lần một đối tượng.
Tìm hiểu thêm về nhân bản ở đây

Đồng bộ hóa là gì? Khóa cấp đối tượng và khóa cấp lớp?

Đồng bộ hóa đề cập đến đa luồng. Một khối mã được đồng bộ hóa chỉ có thể được thực thi bởi một luồng tại một thời điểm. Java cho phép bạn xử lý nhiều luồng cùng một lúc. Điều này có thể dẫn đến hai hoặc nhiều luồng muốn truy cập vào cùng một trường. Đồng bộ hóa giúp tránh các lỗi bộ nhớ xảy ra khi sử dụng tài nguyên bộ nhớ không đúng cách. Khi một phương thức được khai báo là đã đồng bộ, luồng sẽ giữ màn hình của nó. Nếu một luồng khác cố gắng truy cập một phương thức được đồng bộ hóa tại thời điểm này, luồng đó sẽ bị chặn và chờ màn hình rảnh. Đồng bộ hóa trong Java được thực hiện bằng từ khóa đồng bộ hóa đặc biệt . Bạn có thể đánh dấu các khối hoặc phương thức riêng lẻ trong lớp của mình theo cách này. Từ khóa được đồng bộ hóa không thể được sử dụng cùng với các biến hoặc thuộc tính của lớp. Khóa cấp đối tượng là một cơ chế khi bạn muốn đồng bộ hóa một phương thức không tĩnh hoặc khối mã không tĩnh để chỉ một luồng có thể thực thi khối mã trên một phiên bản nhất định của lớp. Điều này phải luôn được thực hiện để làm cho luồng cá thể của lớp được an toàn. Khóa cấp độ lớp ngăn nhiều luồng đi vào một khối được đồng bộ hóa cho tất cả các phiên bản có sẵn của lớp. Ví dụ: nếu có 100 phiên bản của lớp DemoClass thì chỉ có 1 luồng có thể thực thi demoMethod() bằng cách sử dụng một trong các biến tại một thời điểm nhất định. Điều này phải luôn được thực hiện để đảm bảo an toàn cho luồng tĩnh. Tìm hiểu thêm về đồng bộ hóa tại đây.

Sự khác biệt giữa chế độ ngủ() và chờ đợi() là gì?

Sleep()là một phương pháp được sử dụng để trì hoãn quá trình trong vài giây. Trong trường hợp wait(), luồng ở trạng thái chờ cho đến khi chúng ta gọi phương thức notify()hoặc notifyAll(). Sự khác biệt chính là wait()nó nhả khóa màn hình trong khi sleep()không nhả khóa. Wait()được sử dụng cho các ứng dụng đa luồng, sleep()được sử dụng đơn giản để tạm dừng thực thi luồng. Thread.sleep()đặt luồng hiện tại ở trạng thái "Không thể chạy được" trong một khoảng thời gian nhất định. Chuỗi lưu trạng thái của màn hình trước khi phương thức này được gọi. Nếu một thread khác gọi t.interrupt(), thread “ngủ quên” sẽ thức dậy. Lưu ý rằng đây sleep()là một phương thức tĩnh, nghĩa là nó luôn ảnh hưởng đến luồng hiện tại (luồng thực thi phương thức đó sleep()). Một lỗi phổ biến là gọi một chủ đề khác ở t.sleep()đâu t; ngay cả khi luồng hiện tại gọi phương thức đó sleep()không phải là tmột luồng. Object.wait()gửi luồng hiện tại sang trạng thái "Không thể chạy được" trong một thời gian, giống như sleep(), nhưng với một số sắc thái. Wait()được gọi là một đối tượng, không phải một sợi dây; chúng tôi gọi đối tượng này là “đối tượng khóa”. Trước khi gọi lock.wait(), luồng hiện tại phải được đồng bộ hóa với “đối tượng khóa”; wait()sau đó, nó sẽ giải phóng khóa này và thêm chuỗi vào “danh sách chờ” được liên kết với khóa này. Sau đó, một luồng khác có thể đồng bộ hóa với cùng một đối tượng khóa và gọi phương thức lock.notify(). Phương pháp này sẽ "đánh thức" luồng gốc vẫn đang chờ. Về nguyên tắc, wait()/ notify()có thể so sánh với sleep()/ interrupt(), chỉ có thread đang hoạt động không cần con trỏ trực tiếp tới thread đang ngủ, nó chỉ cần biết đối tượng khóa chung. Đọc sự khác biệt chi tiết ở đây.

Có thể gán null cho biến này cho biến tham chiếu không?

Không, bạn không thể. Trong Java, vế trái của toán tử gán phải là một biến. "Đây" là một từ khóa đặc biệt luôn cung cấp phiên bản hiện tại của lớp. Nó không chỉ là bất kỳ biến nào. Tương tự, null không thể được gán cho một biến bằng từ khóa “super” hoặc bất kỳ từ khóa tương tự nào khác.

Sự khác biệt giữa && và & là gì?

&- theo bit và &&- logic.
  1. &đánh giá cả hai mặt của hoạt động;
  2. &&đánh giá phía bên trái của hoạt động. Nếu đúng, nó tiếp tục đánh giá phía bên phải.
Nhìn vào đây để hiểu sâu hơn.

Làm cách nào để ghi đè các phương thức bằng() và hachCode()?

hashCode()equals()các phương thức được định nghĩa trong lớp Object, là lớp cha của các đối tượng Java. Vì lý do này, tất cả các đối tượng Java đều kế thừa cách triển khai mặc định cho các phương thức. Phương thức này hashCode()được sử dụng để lấy một số nguyên duy nhất cho một đối tượng nhất định. Số nguyên này dùng để xác định vị trí của một đối tượng khi đối tượng đó cần được lưu trữ, ví dụ như HashTable. Theo mặc định, hashCode()trả về integerbiểu diễn địa chỉ của vị trí bộ nhớ nơi đối tượng được lưu trữ. Phương thức này equls(), như tên gọi của nó, được sử dụng để kiểm tra xem hai đối tượng có bằng nhau hay không. Việc triển khai mặc định sẽ kiểm tra các tham chiếu đối tượng để xem chúng có bằng nhau hay không. Dưới đây là những hướng dẫn quan trọng để tải lại các phương pháp này:
  1. Luôn sử dụng các thuộc tính đối tượng giống nhau khi tạo hashCode()equals();
  2. Đối diện. Những thứ kia. xnếu nó trả về true cho một số đối tượng y x.equals(y)thì nó y.equals(x)sẽ trả về true;
  3. Tính phản xạ. Đối với bất kỳ đối tượng nào x x.equals(x)cũng phải trả về true;
  4. Tính nhất quán. Đối với bất kỳ đối tượng nào xy x.equals(y)trả về kết quả tương tự nếu thông tin được sử dụng trong so sánh không thay đổi;
  5. Tính chuyển tiếp. Đối với bất kỳ đối tượng nào xy, znếu x.equals(y)nó trả về true và y.equals(z)trả về true, thì nó x.equals(z)sẽ trả về true;
  6. Bất cứ khi nào một phương thức được gọi trên cùng một đối tượng trong quá trình thực thi ứng dụng, nó sẽ trả về cùng một số trừ khi thông tin được sử dụng thay đổi. hashCodecó thể trả về các giá trị khác nhau cho các đối tượng giống hệt nhau trong các phiên bản ứng dụng khác nhau;
  7. Nếu hai đối tượng bằng nhau equalsthì chúng hashCodephải trả về cùng một giá trị;
  8. Yêu cầu ngược lại là tùy chọn. Hai đối tượng không bằng nhau có thể trả về cùng một mã băm. Tuy nhiên, để cải thiện hiệu suất, tốt hơn là để các đối tượng khác nhau trả về các mã khác nhau.
Đọc sự thật thú vị về các phương pháp này ở đây.

Hãy cho chúng tôi biết về công cụ sửa đổi quyền truy cập

Các lớp, trường, hàm tạo và phương thức Java có thể có một trong bốn công cụ sửa đổi truy cập khác nhau: riêng tư Nếu một phương thức hoặc biến được đánh dấu là riêng tư thì chỉ mã trong cùng một lớp mới có thể truy cập vào biến hoặc gọi phương thức đó. Mã bên trong các lớp con không thể truy cập vào một biến hoặc phương thức, cũng như không thể truy cập nó từ bất kỳ lớp nào khác. Công cụ sửa đổi truy cập riêng thường được sử dụng nhiều nhất cho hàm tạo, phương thức và biến. mặc định Công cụ sửa đổi truy cập mặc định được khai báo nếu công cụ sửa đổi hoàn toàn không được chỉ định. Công cụ sửa đổi này có nghĩa là có thể lấy được quyền truy cập vào các trường, hàm tạo và phương thức của một lớp nhất định bằng mã bên trong chính lớp đó, mã bên trong các lớp trong cùng một gói. Các lớp con không thể truy cập các phương thức và biến thành viên của siêu lớp nếu chúng được khai báo là mặc định , trừ khi lớp con đó nằm trong cùng gói với siêu lớp. protected Công cụ sửa đổi protected hoạt động giống như default , ngoại trừ các lớp con cũng có thể truy cập các phương thức và biến được bảo vệ của siêu lớp. Tuyên bố này đúng ngay cả khi lớp con không nằm trong cùng gói với lớp cha. public Công cụ sửa đổi truy cập công khai có nghĩa là tất cả mã có thể truy cập vào lớp, các biến, hàm tạo hoặc phương thức của nó, bất kể mã đó nằm ở đâu. Lõi Java.  Câu hỏi phỏng vấn phần 3 - 2

Người thu gom rác là gì? Chúng ta có thể gọi anh ấy được không?

Thu gom rác là một tính năng quản lý bộ nhớ tự động trong nhiều ngôn ngữ lập trình hiện đại, chẳng hạn như Java và các ngôn ngữ trong NET.Framework. Các ngôn ngữ sử dụng bộ sưu tập rác thường diễn giải việc thu thập rác trong một máy ảo như JVM. Việc thu gom rác có hai mục đích: mọi bộ nhớ không sử dụng sẽ được giải phóng và bộ nhớ sẽ không được giải phóng nếu chương trình vẫn sử dụng nó. Bạn có thể chạy bộ sưu tập rác theo cách thủ công không? Không, System.gc()nó mang lại cho bạn nhiều quyền truy cập nhất có thể. Tùy chọn tốt nhất là gọi phương thức này System.gc(), phương thức này sẽ gợi ý cho trình thu gom rác rằng nó cần chạy. Không có cách nào để chạy nó ngay lập tức vì trình thu gom rác không mang tính quyết định. Ngoài ra, theo tài liệu, OutOfMemoryErrornó sẽ không được chuyển tiếp nếu máy ảo không giải phóng được bộ nhớ sau khi thu gom rác đầy đủ. Tìm hiểu thêm về trình thu gom rác tại đây.

Từ khóa gốc có nghĩa là gì? Giải thích chi tiết

Từ khóa gốc được sử dụng để chỉ ra rằng phương thức này được triển khai bằng ngôn ngữ lập trình không phải là tệp Java. Phương pháp bản địa đã được sử dụng trong quá khứ. Trong các phiên bản Java hiện tại, điều này ít được yêu cầu hơn. Hiện tại, các phương pháp gốc là cần thiết khi:
  1. Bạn phải gọi một thư viện từ Java được viết bằng ngôn ngữ khác.
  2. Bạn cần quyền truy cập vào tài nguyên hệ thống hoặc phần cứng chỉ có thể được truy cập bằng ngôn ngữ khác (thường là C). Trên thực tế, nhiều chức năng hệ thống tương tác với máy tính thực (như đĩa hoặc dữ liệu mạng) chỉ có thể được gọi bằng phương thức gốc.
Những nhược điểm của việc sử dụng thư viện phương thức gốc cũng rất đáng kể:
  1. JNI/JNA có thể làm mất ổn định JVM, đặc biệt nếu bạn cố gắng làm điều gì đó phức tạp. Nếu phương thức gốc của bạn làm sai điều gì đó thì có khả năng xảy ra lỗi JVM. Ngoài ra, những điều tồi tệ có thể xảy ra nếu phương thức gốc của bạn được gọi từ nhiều luồng. Và như thế.
  2. Việc gỡ lỗi một chương trình bằng mã gốc sẽ khó khăn hơn .
  3. Mã gốc yêu cầu xây dựng các khung riêng biệt, điều này có thể gây ra sự cố khi chuyển sang nền tảng khác.

Tuần tự hóa là gì?

Trong khoa học máy tính, trong bối cảnh lưu trữ và truyền dữ liệu, tuần tự hóa là quá trình dịch cấu trúc dữ liệu hoặc trạng thái của một đối tượng sang định dạng có thể được lưu trữ và truy xuất sau này trong môi trường điện toán khác. Sau khi nhận được một loạt bit, chúng được tính toán lại theo định dạng tuần tự hóa và có thể được sử dụng để tạo một bản sao giống hệt về mặt ngữ nghĩa của đối tượng ban đầu. Java cung cấp tính năng tuần tự hóa tự động, yêu cầu đối tượng triển khai giao diện java.io.Serializable. Việc triển khai giao diện đánh dấu lớp là "có thể tuần tự hóa". Giao diện java.io.Serializable không có các phương thức tuần tự hóa, nhưng lớp tuần tự hóa có thể tùy ý xác định các phương thức sẽ được gọi như một phần của quy trình tuần tự hóa/khử tuần tự hóa. Khi thực hiện thay đổi đối với các lớp, bạn cần xem xét lớp nào sẽ tương thích và không tương thích với việc tuần tự hóa. Bạn có thể đọc hướng dẫn đầy đủ ở đây. Tôi sẽ đưa ra những điểm quan trọng nhất: Những thay đổi không tương thích:
  1. Xóa một trường;
  2. Di chuyển một lớp lên hoặc xuống trong hệ thống phân cấp;
  3. Thay đổi trường không tĩnh thành tĩnh hoặc không nhất thời thành nhất thời;
  4. Thay đổi kiểu dữ liệu nguyên thủy đã khai báo;
  5. Thay đổi phương thức WriteObjectđể ReadObjectchúng không còn ghi hoặc đọc các trường theo mặc định;
  6. Thay đổi lớp Serializablethành Externalizablehoặc ngược lại;
  7. Thay đổi một lớp enum thành một lớp không enum hoặc ngược lại;
  8. Loại bỏ Serializablehoặc Externalizable;
  9. Thêm writeReplacemột readResolvephương thức vào một lớp.
Thay đổi tương thích:
  1. Thêm các trường;
  2. Thêm/xóa lớp;
  3. Thêm phương thức WriteObject/ReadObject[phương thức defaultReadObjecthoặc defaultWriteObjectphải được gọi ngay từ đầu];
  4. Phương pháp loại bỏ WriteObject/ReadObject;
  5. Phép cộng java.io.Serializable;
  6. Thay đổi quyền truy cập trường;
  7. Thay đổi trường tĩnh thành không tĩnh hoặc tạm thời thành không nhất thời .
Liên kết tới các phần trước: Java Core. Câu hỏi phỏng vấn, phần 1 Java Core. Câu hỏi phỏng vấn phần 2 Bài viết gốc Chúc bạn học tập vui vẻ!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION