Mục lục
Kiến Thức Cơ Bản về Java
- Sự khác nhau giữa JRE, JVM và JDK là gì?
Trả lời: JDK dùng để phát triển (bao gồm JRE), JRE dùng để chạy các chương trình Java (bao gồm JVM và thư viện), còn JVM là máy ảo thực thi mã bytecode của Java. - Có những loại access modifier nào?
Trả lời: private (chỉ trong class), default (trong package), protected (trong package và lớp con), public (truy cập mọi nơi). - Từ khóa
final
có ý nghĩa gì?
Trả lời: Áp dụng cho biến (không thể thay đổi giá trị sau khởi tạo), phương thức (không thể bị ghi đè), hoặc class (không thể có lớp con). - Giá trị mặc định của các biến là gì?
Trả lời: Các kiểu số là 0, boolean là false, char là ‘\u0000’, và các object (bao gồm String) là null. - Bạn biết gì về hàm
main()
?
Trả lời: Đây là điểm bắt đầu của một ứng dụng Java:public static void main(String[] args) {}
. - Bạn biết những phép toán và toán tử logic nào?
Trả lời: &, &&, |, ||, ^, !, &=, |=, ^=, ==, !=, ?:. - Toán tử lựa chọn tam ngôi là gì?
Trả lời: Toán tử điều kiện có dạng `điều_kiện ? biểu_thức1 : biểu_thức2`, trả về biểu thức1 nếu điều kiện đúng, và biểu thức2 nếu sai. - Bạn biết những phép toán bitwise nào?
Trả lời: ~, &, &=, |, |=, ^, ^=, >>, >>=, >>>, >>>=, <<, <<=. - Toán tử
assert
được dùng để làm gì?
Trả lời: Dùng để kiểm tra các giả định trong mã; nếu biểu thức boolean là false, một AssertionError sẽ được ném ra. - Literal là gì?
Trả lời: Các giá trị hằng được chỉ định rõ ràng trong mã chương trình. - Autoboxing trong Java là gì và các quy tắc đóng gói các kiểu dữ liệu nguyên thủy vào lớp Wrapper?
Trả lời: Chuyển đổi ngầm định các kiểu nguyên thủy sang các đối tượng lớp wrapper tương ứng, mà không cần dùng constructor tường minh. - Generics là gì?
Trả lời: Các tính năng ngôn ngữ cho phép định nghĩa và sử dụng các kiểu và phương thức tham số hóa, mang lại an toàn kiểu và khả năng tái sử dụng mã. - «Internationalization» và «localization» là gì?
Trả lời: Internationalization (i18n) là thiết kế ứng dụng để dễ dàng thích ứng với các ngôn ngữ và khu vực khác nhau. Localization (l10n) là điều chỉnh ứng dụng cho một ngôn ngữ hoặc địa phương cụ thể.
Các Khái Niệm Lập Trình Hướng Đối Tượng (OOP)
- Modifier
abstract
được dùng ở đâu và tại sao?
Trả lời: Dùng cho các lớp không thể tạo instance và các phương thức không có triển khai, đóng vai trò như các template cho lớp con. - Định nghĩa khái niệm _«interface»_. Các modifier mặc định cho các trường và phương thức của interface là gì?
Trả lời: Một kiểu hoàn toàn trừu tượng định nghĩa một hợp đồng. Các phương thức mặc định làpublic abstract
(hoặcdefault
/static
từ Java 8); các trường mặc định làpublic static final
. - Lớp trừu tượng khác interface như thế nào? Trong những trường hợp nào nên dùng lớp trừu tượng, và trường hợp nào nên dùng interface?
Trả lời: Lớp trừu tượng có thể có triển khai và trạng thái, hỗ trợ đơn kế thừa. Interface là hoàn toàn trừu tượng (trước Java 8), hỗ trợ đa triển khai, định nghĩa một hợp đồng. Dùng lớp trừu tượng cho quan hệ “là một” có triển khai một phần, dùng interface để định nghĩa các khả năng. - Tại sao một số interface không định nghĩa bất kỳ phương thức nào cả?
Trả lời: Đây là các marker interface, chỉ ra rằng một lớp có một thuộc tính hoặc khả năng nhất định (ví dụ: `Cloneable`). - Tại sao phương thức của interface không thể khai báo với modifier
final
?
Trả lời: Phương thức của interface mặc định là abstract (phải được triển khai), điều này mâu thuẫn với `final` (không thể bị ghi đè). - Cái nào có mức độ trừu tượng cao hơn – _class_, _abstract class_, hay _interface_?
Trả lời: Interface. - Một đối tượng có thể truy cập thành viên của lớp được khai báo là
private
không? Nếu có, bằng cách nào?
Trả lời: Có, từ bên trong lớp, lớp lồng nhau, hoặc thông qua các phương thức getter/setter public. Reflection cũng có thể bỏ qua kiểm soát truy cập. - Thứ tự gọi constructor và khối khởi tạo có tính đến phân cấp lớp là gì?
Trả lời: Khối static (từ cha đến con) -> Khối non-static (từ cha đến con) -> Constructor (từ cha đến con). - Tại sao cần khối khởi tạo và có những loại nào?
Trả lời: Các khối mã ngoài phương thức/constructor để khởi tạo. Các loại: static (chạy một lần khi tải lớp) và non-static (chạy khi tạo đối tượng trước constructor). - Modifier
static
áp dụng cho những cấu trúc Java nào?
Trả lời: Trường, phương thức, lớp lồng nhau, khối khởi tạo, thành viên import. - Khối khởi tạo static được dùng để làm gì trong Java?
Trả lời: Để khởi tạo các thành viên static hoặc thực hiện các hành động khi lớp được tải. - Điều gì xảy ra nếu một ngoại lệ xảy ra trong khối khởi tạo?
Trả lời: Đối với khối static, sẽ ném ra `ExceptionInInitializerError` (hoặc `Error`). Đối với non-static, ngoại lệ gốc sẽ được ném lại (hoặc `Error`). - Ngoại lệ nào được ném ra khi một lỗi xảy ra trong khối khởi tạo lớp?
Trả lời: `ExceptionInInitializerError` cho RuntimeException trong khối static; RuntimeException gốc cho non-static; `Error` cho Error. - Phương thức static có thể bị ghi đè (override) hoặc nạp chồng (overload) không?
Trả lời: Nạp chồng – có. Ghi đè – không (việc chọn phương thức static được thực hiện lúc biên dịch). - Phương thức non-static có thể nạp chồng phương thức static không?
Trả lời: Có, chúng là hai phương thức khác nhau. - Có thể thu hẹp mức độ truy cập/kiểu trả về khi ghi đè phương thức không?
Trả lời: Không được phép thu hẹp mức độ truy cập. Kiểu trả về có thể thu hẹp (covariant return types). - Có thể khi ghi đè phương thức để thay đổi: access modifier, return type, argument type hoặc số lượng, argument names hoặc thứ tự; xóa, thêm, thay đổi thứ tự các phần tử trong phần
throws
?
Trả lời: Không thể thu hẹp access modifier. Có thể thu hẹp return type. Không thể thay đổi kiểu/số lượng/thứ tự argument (đó là nạp chồng). Có thể sửa đổi mệnh đề `throws` (thu hẹp ngoại lệ, thêm RuntimeException). - Làm thế nào để truy cập các phương thức của lớp cha đã bị ghi đè?
Trả lời: Sử dụng từ khóa `super`. - Phương thức có thể được khai báo vừa abstract vừa static đồng thời không?
Trả lời: Không, `abstract` yêu cầu triển khai trong lớp con, trong khi `static` thuộc về chính lớp đó. - Sự khác nhau giữa thành viên instance và thành viên static của lớp là gì?
Trả lời: Thành viên instance thuộc về các đối tượng cụ thể; thành viên static thuộc về chính lớp đó và được chia sẻ bởi tất cả các instance. - Việc khởi tạo các trường static/non-static được phép ở đâu?
Trả lời: Static: khai báo, khối static/non-static. Non-static: khai báo, khối non-static, constructor. - Có những loại lớp nào trong Java?
Trả lời: Top-level (abstract, final), Interfaces, Enum, Nested (static, inner, local, anonymous). - Kể về các lớp lồng nhau. Chúng được sử dụng trong trường hợp nào?
Trả lời: Các lớp được định nghĩa bên trong một lớp khác, dùng để nhóm các lớp chỉ cần thiết cho lớp bao ngoài. Cho phép truy cập các thành viên của lớp bao ngoài. - «Lớp static» là gì?
Trả lời: Một lớp lồng nhau được khai báo với modifier `static`. Nó không yêu cầu một instance của lớp ngoài và không thể truy cập trực tiếp các thành viên non-static của lớp ngoài. - Những đặc điểm khi sử dụng các lớp lồng nhau: static và inner? Sự khác nhau giữa chúng là gì?
Trả lời: Lớp lồng nhau static không cần instance lớp ngoài và không thể truy cập thành viên non-static lớp ngoài. Lớp inner cần instance lớp ngoài và có thể truy cập tất cả thành viên lớp ngoài. - «Lớp local» là gì? Các đặc điểm của nó?
Trả lời: Lớp inner được định nghĩa bên trong một khối (như một phương thức). Chỉ nhìn thấy trong khối đó, không thể là `public`/`private`/`protected`/`static`. Có thể truy cập các biến local `final`. - «Lớp anonymous» là gì? Chúng được sử dụng ở đâu?
Trả lời: Lớp local không có tên, được khai báo và khởi tạo trong một biểu thức duy nhất. Dùng cho các triển khai ngắn gọn, dùng một lần của interface hoặc lớp trừu tượng. - Lớp lồng nhau có thể truy cập trường của lớp bao ngoài bằng cách nào?
Trả lời: Lớp lồng nhau static truy cập trực tiếp trường static của lớp bao ngoài. Lớp inner truy cập trực tiếp tất cả trường của lớp bao ngoài (hoặc qua `OuterClass.this.field` nếu bị che tên). - Định nghĩa khái niệm «constructor».
Trả lời: Một phương thức đặc biệt có cùng tên với lớp, dùng để khởi tạo các đối tượng khi chúng được tạo ra. - «Constructor mặc định» là gì?
Trả lời: Một constructor không có đối số được trình biên dịch tự động cung cấp nếu không có constructor nào được định nghĩa tường minh trong lớp. - Constructor mặc định, constructor sao chép và constructor có tham số khác nhau như thế nào?
Trả lời: Mặc định: không có đối số. Sao chép: nhận một đối tượng cùng lớp để tạo bản sao. Có tham số: nhận đối số để khởi tạo trạng thái đối tượng. - Bạn có thể sử dụng constructor private ở đâu và như thế nào?
Trả lời: Được sử dụng nội bộ trong lớp, thường đi kèm với các phương thức static factory, hoặc bởi các lớp lồng nhau. Ngăn chặn việc khởi tạo từ bên ngoài. - Kể về classloader và tải lớp động.
Trả lời: Classloader chịu trách nhiệm tải các lớp Java vào JVM trong thời gian chạy. Tải lớp động có nghĩa là các lớp được tải theo yêu cầu trong thời gian chạy, không phải tất cả cùng lúc khi chương trình bắt đầu. Phân cấp chuẩn bao gồm Bootstrap, Extension và System classloader. - Reflection là gì?
Trả lời: Một API cho phép kiểm tra và sửa đổi hành vi của các lớp, phương thức và trường trong thời gian chạy.
Quản Lý Bộ Nhớ và Garbage Collection
- Bộ nhớ Heap và Stack trong Java là gì? Sự khác nhau giữa chúng?
Trả lời: Heap lưu trữ các đối tượng và lớp (truy cập toàn cục, được thu gom rác). Stack lưu trữ các biến local kiểu nguyên thủy và tham chiếu đối tượng (mỗi luồng, truy cập nhanh hơn). - Có đúng là các kiểu dữ liệu nguyên thủy luôn được lưu trữ trên stack, và các instance của kiểu dữ liệu tham chiếu trên heap?
Trả lời: Không hoàn toàn. Biến local kiểu nguyên thủy nằm trên stack. Trường kiểu nguyên thủy của một đối tượng nằm trên heap cùng với đối tượng. Các instance đối tượng nằm trên heap. - Các biến được truyền vào phương thức bằng cách nào, theo giá trị hay theo tham chiếu?
Trả lời: Luôn luôn theo giá trị. Với kiểu nguyên thủy, giá trị được sao chép. Với đối tượng, tham chiếu (địa chỉ bộ nhớ) được sao chép. - Garbage collector dùng để làm gì?
Trả lời: Tự động thu hồi bộ nhớ bị chiếm bởi các đối tượng không còn được chương trình tham chiếu. - Garbage collector hoạt động như thế nào?
Trả lời: Nó xác định các đối tượng không thể truy cập (garbage) và giải phóng bộ nhớ mà chúng chiếm giữ. Các phương pháp phổ biến bao gồm đánh dấu (tracing – đánh dấu các đối tượng có thể truy cập) và các thuật toán thu gom khác nhau (copying, mark-and-sweep). - Có những loại garbage collector nào được triển khai trong máy ảo HotSpot?
Trả lời: Serial, Parallel, CMS (Concurrent Mark Sweep), G1 (Garbage-First). - Mô tả thuật toán của một garbage collector được triển khai trong máy ảo HotSpot.
Trả lời: (Ví dụ: Serial GC) Sử dụng thu gom theo thế hệ (Young, Old, Permanent). Thế hệ Young sử dụng sao chép (không gian Eden, Survivor). Thế hệ Old sử dụng mark-sweep-compact. finalize()
là gì? Nó cần thiết để làm gì?
Trả lời: Một phương thức từ `Object` mà garbage collector *có thể* gọi trước khi hủy đối tượng. Dùng để giải phóng tài nguyên, nhưng việc thực thi nó không được đảm bảo hoặc kịp thời.- Điều gì xảy ra với garbage collector nếu phương thức
finalize()
mất nhiều thời gian để thực thi, hoặc nếu một ngoại lệ được ném ra trong quá trình thực thi?
Trả lời: Việc thực thi lâu hoặc ngoại lệ trong `finalize()` chạy trong luồng Finalizer riêng và không dừng quá trình thu gom rác chính, nhưng có thể làm chậm việc dọn dẹp các đối tượng khác có phương thức `finalize()`. - Sự khác nhau giữa
final
,finally
vàfinalize()
?
Trả lời: `final`: từ khóa cho bất biến/không ghi đè. `finally`: khối trong try-catch được đảm bảo thực thi. `finalize()`: phương thức được GC gọi trước khi hủy (không đảm bảo).
Xử Lý Chuỗi
- «String pool» là gì?
Trả lời: Một vùng nhớ đặc biệt trên Heap nơi lưu trữ các String literal và String được interned để tiết kiệm bộ nhớ. - Các đặc điểm của lớp
String
là gì?
Trả lời: Bất biến (immutable), final, literal được lưu trong string pool, hỗ trợ nối chuỗi bằng +, có thể dùng trong switch (từ Java 7). - Tại sao
String
là một lớp bất biến và final?
Trả lời: Tính bất biến cho phép string pool (tiết kiệm bộ nhớ), an toàn luồng (thread safety), bảo mật (mật khẩu, kết nối mạng), và caching mã hash. Final ngăn chặn việc kế thừa và thay đổi hành vi. - Tại sao
char[]
được ưa dùng hơnString
để lưu trữ mật khẩu?
Trả lời: `char[]` có thể được xóa tường minh khỏi bộ nhớ sau khi sử dụng, giảm rủi ro lộ dữ liệu nhạy cảm từ string pool. - Tại sao String là khóa phổ biến trong
HashMap
trong Java?
Trả lời: Do tính bất biến, mã hash của nó được tính một lần và lưu cache, giúp các thao tác `HashMap` nhanh hơn. - Phương thức
intern()
trong lớpString
làm gì?
Trả lời: Thêm chuỗi vào string pool hoặc trả về tham chiếu đến một chuỗi đã tồn tại có cùng giá trị trong pool. - Các chuỗi có thể được sử dụng trong câu lệnh
switch
không?
Trả lời: Có, từ Java 7. So sánh có phân biệt chữ hoa/thường và sử dụng `equals()`. - Sự khác biệt chính giữa
String
,StringBuffer
,StringBuilder
là gì?
Trả lời: `String` là bất biến. `StringBuffer` là có thể thay đổi và đồng bộ hóa (thread-safe). `StringBuilder` là có thể thay đổi và không đồng bộ hóa (nhanh hơn, không thread-safe).
Các Phương Thức của Lớp Object (equals
, hashCode
, clone
)
- Lớp
Object
là gì? Nó có những phương thức nào?
Trả lời: Lớp gốc của tất cả các lớp trong Java. Các phương thức bao gồm `equals()`, `hashCode()`, `toString()`, `getClass()`, `clone()`, `notify()`, `notifyAll()`, `wait()`, `finalize()`. - Tại sao cần phương thức
equals()
? Nó khác với toán tử==
như thế nào?
Trả lời: `equals()` so sánh nội dung/trạng thái đối tượng (định nghĩa sự tương đương). `==` so sánh tham chiếu đối tượng (địa chỉ bộ nhớ). - Nếu bạn muốn ghi đè phương thức
equals()
, cần đáp ứng những điều kiện nào? Mối quan hệ tương đương được tạo ra bởiequals()
có những tính chất gì?
Trả lời: Phải thỏa mãn: Phản xạ (Reflexivity), Đối xứng (Symmetry), Bắc cầu (Transitivity), Nhất quán (Consistency), và `x.equals(null)` là false. - Các quy tắc để ghi đè phương thức
Object.equals()
.
Trả lời: Sử dụng `==` để kiểm tra cùng đối tượng, `instanceof` hoặc `getClass()` để kiểm tra kiểu, ép kiểu về đúng kiểu, so sánh các trường quan trọng. - Mối quan hệ giữa
hashCode()
vàequals()
là gì? Nếuequals()
bị ghi đè, có những phương thức nào khác nên được ghi đè không?
Trả lời: Nếu `equals()` bị ghi đè, `hashCode() cũng phải bị ghi đè. Các đối tượng bằng nhau phải có mã hash bằng nhau. - Điều gì xảy ra nếu
equals()
bị ghi đè mà không ghi đèhashCode()
? Có thể phát sinh vấn đề gì?
Trả lời: Vi phạm hợp đồng của `hashCode()`, dẫn đến hành vi không chính xác trong các collection như `HashMap` hoặc `HashSet`. - Các phương thức
hashCode()
vàequals()
được triển khai trong lớpObject
như thế nào?
Trả lời: `equals()` kiểm tra sự bằng nhau của tham chiếu (`this == obj`). `hashCode()` là `native` và thường trả về một giá trị dựa trên địa chỉ bộ nhớ của đối tượng. - Phương thức
hashCode()
dùng để làm gì?
Trả lời: Để trả về mã hash integer cho một đối tượng, chủ yếu được sử dụng bởi các collection dựa trên hash (như `HashMap`, `HashSet`) để lưu trữ và truy xuất hiệu quả. - Các quy tắc để ghi đè phương thức
Object.hashCode()
? Có những khuyến nghị nào về các trường nên được sử dụng khi tính toánhashCode()
?
Trả lời: Phải nhất quán với `equals()`. Sử dụng cùng các trường quan trọng được dùng trong `equals()`. Chọn các trường có khả năng khác biệt cao. - Các đối tượng khác nhau có thể có cùng mã
hashCode()
không?
Trả lời: Có, đây gọi là xung đột (collision) và là có thể xảy ra vì phạm vi mã hash có thể có bị giới hạn (`int`). - Nếu lớp
Point{int x, y;}
triển khai phương thứcequals(Object that) {return this.x == that.x && this.y == that.y;}
nhưng mã hash làint hashCode() {return x;}
, liệu các điểm như vậy có được chèn và truy xuất đúng cách từHashSet
không?
Trả lời: Chúng sẽ được chèn và truy xuất, nhưng hiệu suất sẽ kém trong `HashSet` do xung đột thường xuyên với các điểm có cùng `x` nhưng khác `y`. Hợp đồng của `hashCode()` bị vi phạm. - Các đối tượng khác nhau
(ref0 != ref1)
có thể córef0.equals(ref1) == true
không?
Trả lời: Có, nếu `equals()` được ghi đè để so sánh trạng thái đối tượng thay vì tham chiếu, và trạng thái của chúng bằng nhau. - Các tham chiếu khác nhau đến cùng một đối tượng
(ref0 == ref1)
có thể córef0.equals(ref1) == false
không?
Trả lời: Không, trừ khi `equals()` được triển khai sai và vi phạm tính chất phản xạ. `x.equals(x)` phải là true. - Có thể triển khai phương thức
equals(Object that) {return this.hashCode() == that.hashCode();}
như thế này không?
Trả lời: Nghiêm túc mà nói là không, vì các đối tượng khác nhau có thể có cùng mã hash (xung đột). Chỉ chấp nhận được với triển khai mặc định của `Object` nơi mã hash thường dựa trên địa chỉ bộ nhớ. - Trong phương thức
equals()
, cần kiểm tra xem đối sốequals(Object that)
có cùng kiểu với chính đối tượng đó không. Sự khác nhau giữathis.getClass() == that.getClass()
vàthat instanceof MyClass
là gì?
Trả lời: `getClass() == that.getClass()` kiểm tra cùng lớp chính xác. `instanceof` kiểm tra xem đối tượng có phải là instance của lớp đó hoặc lớp con hay không. `getClass()` thường được ưu tiên cho `equals()` để duy trì tính đối xứng. - Phương thức
equals()
của lớpMyClass
có thể được triển khai như thế này không:class MyClass {public boolean equals(MyClass that) {return this == that;}}
?
Trả lời: Điều này nạp chồng (overload), chứ không phải ghi đè (override), phương thức `Object.equals(Object)`. Phiên bản của `Object` vẫn sẽ được gọi nếu đối số có kiểu `Object`. - Có lớp
Point{int x, y;}
. Tại sao mã hash dạng31 * x + y
được ưa dùng hơnx + y
?
Trả lời: Sử dụng một số nguyên tố làm hệ số nhân (31) tạo ra sự phân bố mã hash tốt hơn, giảm xung đột so với phép cộng đơn giản, vốn sẽ tạo ra cùng mã hash cho (1, 5) và (5, 1). - Kể về việc sao chép đối tượng (object cloning).
Trả lời: Tạo một bản sao của đối tượng đã tồn tại. Lớp `Object` cung cấp phương thức `clone()` cho sao chép nông (shallow copy); sao chép sâu (deep copy) yêu cầu triển khai thủ công hoặc sử dụng serialization. - Sự khác nhau giữa sao chép nông (shallow) và sao chép sâu (deep) là gì?
Trả lời: Sao chép nông sao chép các giá trị nguyên thủy và tham chiếu đối tượng. Sao chép sâu sao chép các giá trị nguyên thủy và tạo các instance mới cho tất cả các đối tượng được tham chiếu. - Phương pháp sao chép nào được ưa dùng hơn?
Trả lời: Sử dụng copy constructor thường được ưu tiên vì an toàn hơn, xử lý các trường final, và tránh các vấn đề với interface `Cloneable` và các triển khai `clone()` một phần trong lớp cha. - Tại sao phương thức
clone()
được khai báo trong lớpObject
, không phải trong interfaceCloneable
?
Trả lời: `clone()` cung cấp cơ chế sao chép nông native. `Cloneable` là một marker interface chỉ ra rằng một lớp *có thể* được sao chép bằng cơ chế này; nếu không, `clone()` sẽ ném ra `CloneNotSupportedException`.
Xử Lý Ngoại Lệ
- Mô tả cây phân cấp ngoại lệ.
Trả lời: Tất cả các ngoại lệ kế thừa từ `Throwable`. Các lớp con trực tiếp là `Error` (các vấn đề nghiêm trọng ở cấp JVM, không nên xử lý) và `Exception` (các vấn đề có thể phục hồi của chương trình). - Bạn biết những loại ngoại lệ nào trong Java, chúng khác nhau như thế nào? «Checked» và «unchecked exceptions» là gì?
Trả lời: Checked exceptions (ví dụ: `IOException`) phải được bắt (`catch`) hoặc khai báo (`throws`). Unchecked exceptions bao gồm `Error` (các vấn đề JVM) và `RuntimeException` (các lỗi chương trình như `NullPointerException`), không yêu cầu xử lý hoặc khai báo tường minh. - Toán tử nào cho phép bạn ném một ngoại lệ một cách tường minh?
Trả lời: Toán tử `throw`. - Từ khóa
throws
có ý nghĩa gì?
Trả lời: Được sử dụng trong chữ ký phương thức để khai báo rằng phương thức đó có thể ném ra một loại ngoại lệ checked đã chỉ định. - Làm thế nào để viết một ngoại lệ của riêng bạn («custom»)?
Trả lời: Tạo một lớp kế thừa từ lớp ngoại lệ cơ sở cần thiết (ví dụ: từ `Exception` cho checked hoặc `RuntimeException` cho unchecked), thường cung cấp các constructor. - Có những «unchecked exceptions» nào?
Trả lời: Các loại phổ biến bao gồm `ArithmeticException`, `NullPointerException`, `IllegalArgumentException`, `IndexOutOfBoundsException`, `ClassCastException`, `IllegalStateException`. - Các lỗi lớp
Error
đại diện cho điều gì?
Trả lời: Các vấn đề nghiêm trọng, thường không thể phục hồi ở cấp JVM (ví dụ: `OutOfMemoryError`, `StackOverflowError`). - Bạn biết gì về
OutOfMemoryError
?
Trả lời: Một `Error` được ném ra khi JVM không thể cấp phát một đối tượng do không đủ bộ nhớ trong một vùng bộ nhớ cụ thể (Heap, PermGen/Metaspace, stack luồng native). - Mô tả hoạt động của khối _try-catch-finally_.
Trả lời: `try` chứa mã có thể ném ngoại lệ. `catch` xử lý các loại ngoại lệ cụ thể. `finally` chứa mã luôn thực thi, bất kể có xảy ra ngoại lệ hay không. - Cơ chế _try-with-resources_ là gì?
Trả lời: Một khối try khai báo các tài nguyên triển khai `AutoCloseable`. Các tài nguyên này được tự động đóng khi kết thúc khối try (ngầm định trong một `finally` được tạo ra). - Có thể sử dụng khối _try-finally_ (không có
catch
) không?
Trả lời: Có, khối `finally` vẫn sẽ thực thi, nhưng bất kỳ ngoại lệ nào được ném ra trong khối `try` sẽ không bị bắt và sẽ lan truyền. - Một khối
catch
có thể bắt nhiều ngoại lệ cùng lúc không?
Trả lời: Có, từ Java 7, sử dụng cú pháp multi-catch (`catch (ExceptionType1 | ExceptionType2 ex)`). - Khối
finally
luôn thực thi chứ?
Trả lời: Gần như luôn luôn. Nó có thể không thực thi trong các tình huống như gọi `System.exit()`, JVM gặp sự cố, hoặc một vòng lặp vô hạn/deadlock trong khối `try` hoặc `catch`. - Có những tình huống nào mà khối
finally
sẽ không được thực thi không?
Trả lời: Có, ví dụ: gọi `System.exit()`, JVM gặp sự cố, hoặc một `Error` không được xử lý làm sập luồng/JVM. - Phương thức _main()_ có thể ném ngoại lệ ra ngoài không, và nếu có, ngoại lệ này sẽ được xử lý ở đâu?
Trả lời: Có, nó có thể. Các ngoại lệ chưa được bắt trong `main()` được xử lý bởi trình xử lý ngoại lệ mặc định của JVM, thường in dấu vết stack và thoát. - Giả sử có một phương thức có thể ném ra
IOException
vàFileNotFoundException
. Các khốicatch
nên theo thứ tự nào? Sẽ có bao nhiêu khốicatch
được thực thi?
Trả lời: `FileNotFoundException` nên được bắt trước `IOException` vì nó là lớp con. Chỉ một khối `catch` (khối khớp đầu tiên) sẽ được thực thi.
Tải Lớp
- Kể về classloader và tải lớp động.
Trả lời: Classloader chịu trách nhiệm tải các lớp Java vào JVM. Tải lớp động có nghĩa là các lớp được tải theo yêu cầu trong thời gian chạy, không phải tất cả cùng lúc khi chương trình bắt đầu. Hệ thống phân cấp chuẩn bao gồm Bootstrap, Extension và System classloader.
Đọc thêm về: Spring Boot Roadmap – Lộ trình học Java Spring Boot năm 2025
Trọn bộ câu hỏi phỏng vấn Java Core – Phiên bản dài, rất dàiii