Câu hỏi phỏng vấn Java

Bài gốc: http://www.javacodegeeks.com/2014/04/java-interview-questions-and-answers.html

Xuyên suốt bài viết, chúng ta cùng thảo luận về lập trình hướng đối tượng, những câu hỏi tổng quát liên quan đến Java và những chức năng của nó, tập hợp(collections) trong Java, bộ dọn rác (garbage collectors), ngoại lệ (exception handling), Java applets, Swing, JDBC, Remote Method Invocation (RMI), Servlets and JSP …

LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG (OBJECT ORIENTED PROGRAMMING)

Java là một ngôn ngữ lập trình mang tính đồng thời (concurrent), class-based và hướng đối tượng. Một vài lợi ích của việc phát triển phần mềm theo hướng đối tượng:

  • Modun hoá việc phát triển mã lệnh, dẫn đến bảo trì và thay đổi đơn giản.
  • Có khả năng tái sử dụng mã lệnh
  • Cải tiến độ tin cậy và mềm dẻo trong mã lệnh.
  • Giúp mã lệnh dễ hiểu hơn.

Lập trình hướng đối tượng có nhiều những đặc tính quan trọng, như encapsultation (tính bao đóng), inheritance (tính kế thừa), polymorphism (tính đa hình) và abstraction(tính trừu tượng). Chúng ta phân tích mỗi đặc tính qua từng phân đoạn.

Encapsulation

Encapsulation (tính bao đóng) cung cấp cho những đối tượng khả năng che dấu tính chất đặc thù và những hành vi bên trong chúng. Mỗi đối tượng cung cấp một số các phương thức, chúng có thể được truy cập từ những đối tượng khác và có thể bị thay đổi dữ liệu bên trong nó. Trong Java, có 3 mức(modifier) truy cập:  public, private và protected. Mỗi mức bắt buộc những quyền truy cập khác nhau từ những lớp (class) khác, dù là cùng hay khác package. Một vài lợi ích khi sử dụng encapsulation:

  • Ẩn những trạng thái (state) của đối tượng cần được bảo vệ.
  • Tăng khả năng bảo trì và sử dụng mã lênh, bởi vì những hành vi của đối tượng có thể độc lập khi bị thay đổi hay mở rộng.
  • Tăng khả năng modun hoá bằng cách tránh những đối tượng tương tác trực tiếp lẫn nhau, trong cách nhờ vả nhau.

Bạn có thể tham khảo thêm một bài hướng dẫn để nắm rõ hơn về đặc tính encapsulation : here

Polymorphism

Polymorphism (tính đa hình) là khả năng của ngôn ngữ lập trình để biểu thị những interface (giao diện) giống nhau cho những kiểu dữ liệu cơ bản khác nhau. Kiểu đa hình là kiểu mà những xử lý bên trong nó có thể được áp dụng lên giá trị của những kiểu khác.

Inheritance

Kế thừa cung cấp cho đối tượng khả năng sử dụng được những trường (field), phương thức (method) từ những lớp khác, lớp đó gọi là lớp cơ bản (lớp cha, base class). Kế thừa cung cấp khả năng tái sử dụng mã lệnh và có thể được sử dụng để thêm những tính năng mới cho một lớp đã có trước nhưng không làm thay đổi lớp đó.

Abstraction

Abstraction một một quá trình để tách biệt những ý tưởng với những thực thể cụ thể và vì vậy, phát triển lớp trong những điều khoản (term) của các chức năng bên trong nhưng không cài đặt chi tiết những chắc năng đó. Java cung cấp khả năng khởi tạo lớp trừu tượng và những lớp trừu tượng đã có như interfaces (không phải cài đặt chi tiết cho tất cả các phương thức trong lớp trừu tượng). Kỹ thuật trừu tượng nhằm giúp tách biệt việc cài đặt chi tiết của lớp từ những hành vi của nó.

Khác biệt giữa AbstractionEncapsulation

Abstraction và encapsulation là những khái niệm bổ sung cho nhau. Abstraction tập trung vào hành vi của đối tượng, encapsulation tập trung vào việc cài đặt hành vi của đối tượng. Encapsulation sẽ đạt được bằng cách ẩn trong tin trạng thái bên trong của một đối tượng và vì vậy, encapsulation cũng là một cách sử dụng cho tính trừu tượng.

NHỮNG CÂU HỎI TỔNG QUÁT VỀ JAVA (GENERAL QUESTIONS ABOUT JAVA)

1. JVM là gì? Tại sao Java là một ngôn ngữ lập trình độc lập nền tảng (Platform Independent Programming Language) ?

Java Virtual Machine (JVM) là một tiến trình như một máy ảo để có thể thực thi được bytecode (Các bạn đọc thêm bytecode theo dường dẫn). Mỗi tập tin mã nguồn trong Java được biên dịch ra một tập tin bytecode và chúng được thực thi bởi JVM. Java được thiết kế để cho phép những chương trình ứng dụng có thể được dựng(build) lên và chạy trên bất kỳ nền tảng nào, mà không cần phải viết lại mã lệnh khác hoặc biên dịch lại mã nguồn cho mỗi nền tảng khác nhau. JVM làm được điều trên, bởi vì JVM có thể nhận biết được các tập lệnh cụ thể và đặc thù của từng nền tảng phần cứng bên dưới.

2. Sự khác nhau giữ JDK và JRE là gì?

JRE (The Java Runtime Environment) cơ bản chính là JVM, nơi mà chương trình được thực thi. Nó còn bao gồm những plugin (trình bổ trợ) cho trình duyệt thực thi applet. JDK (The Java Development) là một bộ phát triển phần mềm đầy đủ các tính năng hỗ trợ cho Java, gồm có JRE, trình biên dịch và những công cụ hỗ trợ khác (như JavaDoc, và Trình gỡ rỗi Java), giúp cho người dùng phát triển, biên dịch và thực thi một chương trình Java.

3. Ý nghĩ của từ khoá “static”(tĩnh) trong Java là gì? Chúng ta có thể override (đè) một hàm private hoặc static trong Java không?

Từ khoá “static” biểu thị cho biến hoặc phương thức có thể được truy cập (sử dụng) mà không cần tạo ra thực thể của lớp chứa nó. Người dùng không thể override(đè) phương thức static trong Java, bởi vì kỹ thuật đè (overriding) phương thức được dựa trên quá trình gán (binding) động khi runtime (khi chương trình đang chạy) và những phương thức static  được gán tĩnh trong thời gian biên dịch. Phương thức tĩnh không ràng buộc với thực thể của lớp nên phương thức tĩnh sẽ không thể override (đè).

4. Chúng ta có thể truy cập một biến không tĩnh(non-static) trong một ngữ cảnh static được không?

Một biến static phụ thuộc vào lớp của nó và giá trị của nó sẽ tồn tại (giữ) cho tất cả các thực thể của lớp đó. Biến static được tạo ra khi lớp chứa đó được tải (load) bởi JVM. Nếu cố gắng truy cập vào một biến non-static (trong hàm static) mà không có trong thực thể nào, thì trình biên dịch sẽ báo lỗi, bởi vì những biến đó(non-static) chưa được khởi tạo và chúng không có ràng buộc với bất kỳ thực thể nào.

5. Java hỗ trợ những kiểu dữ liệu nào? Thế nào là Autoboxing và Unboxing?

8 kiểu dữ liệu cơ bản (nguyên thuỷ, primitive data type) được hỗ trợ trong Java:

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char

Autoboxing là quá trình mà trình biên dịch của Java tự động chuyển đổi giữa kiểu dữ liệu cơ bản (primitive) về đối tượng tương ứng với lớp của kiểu dữ liệu đó. Ví dụ, trình biên dịch sẽ chuyển đổi kiểu dữ liệu int sang Integer, kiểu double sang Double, … tùm lum. Và ngược lại là unboxing.

Đọc thêm : http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

6. Thế nào là phương thức nạp chồng (Overloading) và ghi đè (Overriding) trong Java?

Nạp chồng phương thức (method overrloading) xảy ra khi trong cùng một lớp có nhiều hơn hai phương thức có cùng tên, nhưng khác tham số (số lượng hoặc kiểu). Mặt khác, ghi đè phương thức (method overriding) được dùng trong trường hợp một lớp con muốn định nghĩa lại phương thức đã có ở  lớp cha. Phương thức ghi đè (Overridden methods) phải có tên, số lượng tham số, và kiểu trả về giống với lớp cha. Overriding method cũng không giới hạn việc truy cập vào phương thức nó đã ghi đè.

7. Hàm tạo (Constructor) là gì, Nạp chồng hàm tạo(Constructor Overloading) và sao chép hàm tạo (Copy-Constructor)?

Constructor được gọi khi một đối tượng được tạo ra. Mỗi lớp đều có một constructor. Trong trường hợp người lập trình không khai báo constructor cho lớp, trình biên dịch sẽ tạo một constructor mặc định cho lớp đó. Nạp chồng hàm tạo (Constructor overloading) cũng khá giống với nạp chồng phương thức (method overrloading). Các constructor khác nhau được tạo ra cho mỗi lớp đơn lẽ. Cuối cùng, Java không hỗ trợ sao chép hàm tạo như trong C++, nhưng khác biệt ở chỗ Java sẽ không tạo ra hàm tạo sao chép nếu bạn không tạo ra nó ( chơi chữ chỗ này, Java không hỗ trợ nhưng bạn có thể tự viết cái).

8. Có phải Java hỗ trợ đa thừa kế?

Không, Java không hỗ trợ đa thừa kế. Mỗi lớp có thể extend(kế thừa) chỉ được một lớp, nhưng có thể cài đặt nhiều interface.

9. Sự khác nhau giữa Interface và lớp Abstract (lớp trừu tượng)?

Java cung cấp và hỗ trợ cả abstract class và interface. Cả 2 sự cài đặt đều có chung một số đặc tính, nhưng chúng khác nhau một vài điểm:

  • Tất cả phương thức trong interface là abstract (trừu tượng). Nhưng, trong lớp abstract có thể chứa cả phương thức abstract hoặc không abstract (non-abstract)
  • Một lớp có thể cài đặt (implement) nhiều interface, nhưng chỉ được kế thừa (extend) một lớp abstract.
  • Để cài đặt một interface, lớp đó phải cài đặt tất cả các hàm được định nghĩa trong interface. Tuy nhiên, một lớp có thể không cài đặt tất cả các hàm đã định nghĩa trong lớp abstract. Mặc dù, trong trường hợp này, lớp con cũng phải định nghĩa là lớp abstract.

    Mình giải thích thêm chỗ này: Một lớp extend một lớp trừu tượng có thể không cần định nghĩa lại (override) các hàm non-abstract nhưng bắt buộc phải override các hàm abstract. Nếu lớp con cũng là một lớp abstract thì không cần định nghĩa lại hàm nào cả. Các bạn tìm hiểu thêm về lớp trừu tượng. Vì đây chỉ là phần so sanh với interface nên tác giả nói ý chung.

  • Lớp abstract có thể cài đặt một interface mà không cần cài đặt bất kỳ hàm nào của interface đó.
  • Các biến được định nghĩa trong interface mặc định là final, còn lớp abstract thì có thể không final (non-final).
  • Các thành phần trong interface mặc định là public, còn trong lớp abstract có thể là public, private hoặc protected (tuỳ vào người định nghĩa).
  • Interface là thuần trừu tượng, không thể tạo thực thể cho nó. Một lớp abstract cũng không thể tạo thực thể, nhưng nó có thể được gọi nếu chứa hàm main.

Các bạn có thể xem thêm tại : http://www.javacodegeeks.com/2014/04/abstract-class-versus-interface-in-the-jdk-8-era.html

10. Thế nào là truyền tham chiếu và truyền tham trị?

Khi một đối tượng được truyền bằng tham trị, có nghĩa là truyền giá trị sao chép của nó. Vì vậy, mặc dù có sự thay đổi lên đối tượng đó thì giá trị gốc vẫn không bị thay đổi. Khi một đối tượng được truyền kiểu tham chiếu, thì đối tượng thật không được truyền mà truyền tham chiếu đến nó. Vì vậy, bất cứ sự thay đổi nào lên giá trị được truyền vào sẽ làm thay đổi ở tất cả các nơi sử dụng đối tượng đó.

LUỒNG TRONG JAVA (JAVA THREADS)

11. Khác biệt giữa tiến trình và luồng là gì?

Một tiến trình (process) là sự thực thi của chương trình, trong khi một luồng(thread) là một sự thực thi đơn lẻ có tuần tự bên trong tiến trình. Một tiến trình có thể chứa nhiều luồng. Một luồng đôi khi được xem như một tiến trình nhỏ (tiểu trình, lightweight process).

12. Giải thích sự khác nhau giữa các cách tạo luồng(thread). Cái nào bạn hay dùng hơn (prefer) và tại sao?

Có 3 cách để tạo ra một thread:

  • Một lớp kế thừa (extends) từ lớp Thread
  • Một lớp cài đặt interface Runnable
  • Một chương trình có thể sử dụng framwork Executor, để tạo là một thread pool (giống như cái hố chứa một đống luồng).

Cách hay được sử dụng và được yêu thích là dùng interface Runnable, bởi vì nó không yêu cầu phải tạo một lớp kế thừa từ lớp Thread. Trong trường hợp ứng dụng thiết kế yêu cầu sử dụng đa kế thừa, chỉ có interface mới có thể giúp giải quyết vấn đề. Ngoài ra, thread pool rất hiểu quả và có thể được cài đặt, sử dụng rất hơn giản.

13. Giải thích các trạng thái khả dụng (available) của thread trong high-level (cấp độ cao)

Trong suốt quá trình thực thi của nó, một thread có thể giữ một trong những trạng thái:

  • Runnable: Một thread sẵn sàng để chạy, nhưng không cần thiết chạy ngay lập tức.
  • Running: Tiến trình đang chạy mã lệnh trong luồng.
  • Waiting: Một thread trong trạng thái dừng(nghẽn, blocked) để chờ một tiến trình khác chạy chấm dứt.
  • Sleeping: Một thread đang ngủ (dừng hoạt động, sleeping).
  • Blocked on I/O: Chờ một thao tác I/O(xuất nhập) hoàn thành.
  • Blocked on Synchronization: Đang chờ trong trạng thái bị khoá.
  • Dead: Một thread thực thi xong các dòng lệnh của nó.

14. Sự khác biệt giữa phương thức đồng bộ (synchronized method) và khối đồng bộ (synchronized block)?

Trong lập trình Java, mỗi đối tượng đều có một khoá (chốt, lock). Một thread có thể chốt (khoá) được đối tượng bằng cách sử dụng từ khóa  synchronized. Từ khoá synchronized có thể được áp dụng trong phương thức (method, cách khoá dở ẹt (coarse) ) và khối lệnh (block, cách khoá tốt (fine)).

Tác giả trả lời cho câu hỏi này khá chung và không đầy đủ cho câu hỏi, các bạn tham khảo thêm đường dẫn http://java67.blogspot.com/2013/01/difference-between-synchronized-block-vs-method-java-example.html (Mình sẽ cố gắng dịch bài này sau)

15. Một thread đồng bộ xảy ra bên trong một monitor như thế nào? Những cấp đồng bộ có thể được áp dụng là gì?

JVM sử dụng các khoá như sự liên kết với các monitor (các chương trình giám sát). Một monitor cơ bản là một người bảo vệ quan sát các mã lệnh tuần tự và đảm bảo chỉ một thread duy nhất tại một thời điểm thực thi được các dòng lệnh đồng bộ. Mỗi monitor gắn sát với một đối tượng tham chiếu. Thread sẽ không được phép thực tin mã lệnh trong khi nó (mã lệnh) đang được khoá (lock).

16. Deadlock(Khoá chết) là gì? 

Xảy ra khi 2 tiến trình đợi nhau hoàn thành, trước khi chạy. Kết quả của quá trình là cả 2 tiến trình không bao giờ kết thúc.

17. Làm sao để đảm bảo N thread truy cập vào N tài nguyên (resources) mà deadlock không xảy ra?

Một cách đơn giản để tránh deadlock trong khi sử dụng N thread là phải áp đặt thứ tự của các khoá (lock) và ép các thread theo sự sắp sếp đó. Vì vậy, tất cả các thread khoá và mở khoá như nhau thì deadlock sẽ không xảy ra.

Thread (Concurrency, Multithread) là chủ đề khá khó trong lập trình nói chung và cho Java nói riêng, các câu hỏi của tác giả mình thấy khá sơ sài và câu trả lời rất chung chung. Các bạn nên đào sau tìm hiểu về thread vì đây là chủ đề rất quan trọng trong lập trình, giúp bạn có cái nhìn sâu sắc hơn về hệ thống và luồng xử lý trong một chương trình phức tạp ngày nay.

TẬP HỢP TRONG JAVA (JAVA COLLECTIONS)

18. Những interface cơ bản trong Java Collections Framework?

Java Collection Framework cung cấp những thiết kế các interface và class để hỗ trợ việc thao tác trên tập hợp của các đối tuợng. Những interface cơ bản nhất đuợc cung cấp trong Java Collections Framework:

  • Collection, biểu thị cho nhóm các đối tuợng, những đối tuợng này đưọc gọi là phần tử của tập hợp.
  • Set, là một tập hợp mà không chứa những phần từ trùng nhau.
  • List, là một tập hợp đã sắp sếp và có thể chứa những phần tử trùng nhau.
  • Map, là một đối tuợng mà ánh xạ các khoá vào các giá trị và không chứa những khoá trùng nhau.

19. Tại sao Colection (interface) không kế thừa (extend) interface Cloneable và Serializable?

Interface Collection biểu thị một nhóm các đối tuợng biết đến như phần tử trong tập hợp. Mỗi sự cài đặt cụ thể của Collection có thể lựa chọn cách riêng để bảo trì và sắp sếp phần tử của nó (lớp cài đặt). Một số tập hợp chấp nhập trùng khoá, trong khi một số thì không. Mục đích và ý nghĩa của clone(bản sao) và serialization đuợc sử dụng trong những cài đặt thật. Vì vậy, những cài đặt cụ thể của tập hợp sẽ quyết định chúng sẽ sử dụng clone và serialization như thế nào.

20. Thế nào là Iterator?

Interface Iterator cung cấp một số các phương thức để duyệt(lặp) qua các phần tử bất kỳ tập hợp nào. Mỗi interface Collection trong Java đều chứa một phương thức iterator để trả về một thực thể của interface Iterator. Iterator có khả năng xoá những phần từ tập hợp trong quá trình lặp.

21. Sự khác biệt giữa Iterator và ListIterator?

Vài sự khác nhau của 2 interface trên:

  • Iterator đưọc sử dụng để duyệt qua(lặp qua) các interface Set và List, trong khi ListIterator chỉ đuợc sử dụng để duyệt qua List
  • Iterator có thể duyệt qua tập hợp chỉ một huớng, trong khi ListIterator có thể duyệt qua List tất cả các huớng (2 huớng).
  • ListIterator cài đặt interface Iterator và chứa thêm một số chức năng mới, như thêm mới một phần tử, thay thế phần từ, lấy chỉ mục (index) cho phần từ kế truớc hay sau nó, etc.

22. Sự khác nhau giữa fail-fast và fail-safe?

Thuộc tính fail-fast trong interface Iterator làm việc với bản sao của tập hợp và vì vậy, nó không ảnh huởng đến bất kỳ sự thay đổi trong tập hợp. Tất cả các lớp tập hợp trong java.util là fail-fast, trong khi các lớp trong java.util.concurrent là fail-safe. Fail-fast ném ra ngoại lệ ConcurrentModificationException, trong khi fail-safe không bao giờ ném ra ngoại lệ như thế.

23. HashMap trong Java làm việc như thế nào?

HashMap trong Java chứa những cặp khoá-giá trị. HashMap yêu cầu một hàm băm và sử dụng phương thức hashCode và equals để thêm vào và lấy lại phần từ một tập hợp tương ứng. Khi hàm put (đẩy vào, thêm vào) đuợc gọi, HashMap tính toán giá trị hash(giá trị băm) của khoá và lưu trữ cặp giá trị (key-value) đuợc đánh chỉ mục thích hợp vào tập hợp. Nếu khoá đã tồn tại, giá trị của nó đuợc cập nhập(update) bằng giá trị mới. Một vài đặc tính quan trọng của HashMap là mức chứa của nó, yếu tố tải dữ liệu và ngưỡng thay đổi kích thước tập hợp.

24. Sự quan trọng của hàm hashCode và equals là gì?

HashMap trong Java sử dụng 2 hàm hashCode và equals để xác định chỉ mục của cặp khoá-giá trị(key-value). 2 hàm này còn được sử dụng khi chúng ta yêu cầu giá trị của một khoá cụ thể. Nếu 2 hàm này không đuợc cài đặt(implement) chính xác, như 2 khoá khác nhau lại cho ra hash code (giá trị đã băm) giống nhau và vì vậy, chúng sẽ đuợc xem như là bằng nhau trong tập hợp.Xa hơn nữa, 2 hàm này còn sử dụng để phát hiện trùng lặp. Nên, việc cài đặt 2 hàm là yếu tốt then chốt để kiểm tra tính đúng đắn của HashMap.

25. Sự khác nhau giữa HashMap và Hashtable?

Cả HashMap và Hashtable đều cài đặt interface Map và vì vậy, chúng có nhiều đặc tính giống nhau. Tuy nhiên, chúng khác nhau vài điểm:

  • HashMap chấp nhận giá trị khoá hoặc giá trị(value) null, trong khi Hashtable thì không (cả key và value).
  • Hashtable thì đồng bộ (synchronized), HashMap thì không. Vì vậy, HashMap đuợc sử dụng nhiều trong môi truờng đơn luồng(single-thread), còn Hashtable sử dụng trong môi truờng đa luồng (multi-thread).
  • HashMap cung cấp bộ khoá cho nó và ứng dụng có thể lặp(duyệt) qua chúng. Vì vậy, HashMap là fail-fast(câu hỏi 22).Hastable thì cung cấp kiểu liệt kê (Enumeration) cho các khoá.
  • Hashtable đuợc xem như lớp legacy.

Mình không dịch đưọc từ legacy, mình thêm đuờng dẫn để các bạn đọc thêm legacy classes và interfaces là gì http://www.rapidprogramming.com/tutorial/JAVA-Legacy-classes-interfaces-145.

26.Sự khác nhau giữa Array và ArrayList? Khi nào chúng ta sẽ sử dụng Array thay vì ArrayList?

Array và ArrayList khác nhau :

  • Array có thể chứa kiểu dữ liệu cơ bản và đối tưọng, trong khi ArrayList chỉ chứa đối tuợng.
  • Array cố định số luợng phần từ, ArrayList thì động
  • ArrayList cung cấp nhiều hàm và chức năng hơn như addAll, removeAll, iterator, vv.
  • Đối với danh sách kiểu dữ liệu cơ bản, tập hợp (collection) sử dụng autoboxing để giảm viết mã. Tuy nhiên, điều đó sẽ làm chúng (collection) chạy chậm hơn khi làm việc với mảng kiểu dữ liệu cơ bản (fixed).

27. Sự khác biệt giữa ArrayList và LinkedList? 

Cả 2 ArrayList và LinkedList đều cài đặt interface List, nhưng chúng có vài điểm khác biệt:

  • ArrayList là một kiểu cấu trúc dữ liệu chỉ mục như Array. Nó cung cấp sự truy cập ngẫu nhiên vào phần tử với hiệu năng là O(1). Còn LinkedList chứa dữ liệu như một danh sách các phần tử và mỗi phần tử liên kết với phần tử truớc và sau nó. Trong truờng hợp này, thao tác tìm kiếm một phần tử mất thời gian là O(n).
  • Thao tác thêm và xoá phần tử của LinkedList sẽ nhanh hơn so với ArrayList, bởi vì không cần phải thay đổi kích thuớc hay cập nhập lại chỉ mục khi một phần tử được thêm vào.
  • ListedList tiêu hao nhiều bộ nhớ hơn ArrayList bởi vì mỗi phần tử (node) trong LinkedList chứa 2 tham chiếu, một cho phần tử phía trước và một cho phần tử sau nó.

28. 2 interface Comparable và Comparator là gì? Liệt kê điểm khác nhau giữa chúng.

Java cung cấp một interface là Comparable chỉ chứa một phuơng thức compareTo. Phương thức này so sánh 2 đối tuợng, để sắp đặt trật tự giữa chúng. Đặt biệt nó trả về một số dương, 0 hoặc số âm để cho biết đối tuợng nhận vào sẽ nhỏ hơn, bằng hay lớn hơn nó. Java cung cấp interface Comparator chứa 2 phuơng thức là compare và equals. Phuơng thức compare nhận vào 2 tham số và xác định trật tự (order) giữa chúng. Hàm trả về số duơng, 0 hoặc số âm để biểu thị tham số đầu tiên sẽ nhỏ, bằng hay lớn hơn tham số thứ 2. Phương thức equals yêu cầu một đối số là một đối tuợng và giúp xác định đối tuợng truyền vào có phải là một comparator. Hàm trả về true nếu đối tuợng truyền vào là một comparator và đuợc sắp xếp như một comparator.

29. Thế nào là Priority Queue?

PriorityQueue là một queue(hàng đợi) không giới hạn (unbound), dựa trên priority heap và phần tử của nó đuợc sắp sắp theo trật tự ban đầu. Tại thời gian tạo ra nó, chúng ta sẽ cung cấp một Comparator với nhiệm vụ là sắp xếp thứ tự các phần tử của PriorityQueue. PriorityQueue không chập giá trị null, bởi những đối tượnng đó không hề có thứ tự. Cuối cùng, PriorityQueue không thread-safe và nó sử dụng thời gian O(log(n)) cho thao tác enqueue(đẩy vào hàng đợi)  và dequeue (lấy ra khỏi hàng đợi).

30. Thế nào là Big-O notation, liệt kê một số ví dụ  trên các cấu trúc dữ liệu khác nhau?

Ký hiện big-O đơn giản là biểu thị khả năng của thuật toán khi mở rộng hay tính toán trong tình huống xấu nhất, như số luợng phần từ trong cấu trúc dữ liệu tăng lên. Ký hiệu O ngoài ra còn đuợc sử dụng để biểu thị cho cách hành vi khác như mức sử dụng bộ nhớ. Bởi vì những lớp Collection thật ra cũng là những cấu trúc dữ liệu, chúng ta thuờng sử dụng big-O để lựa chọn phuơng pháp cài đặt tốt nhất để sử dụng, dựa vào thời gian, bộ nhớ và kết quả. Big-O đưa ra chỉ số tốt về hiệu năng của dữ liệu lớn.

31. Khác biệt giữa mảng có thứ tự và mảng không thứ tự?

Lợi ích chính của mảng có thứ tự là thời gian tìm kiếm có độ phức tạp là O(logn), trong khi mảng không có thứ tự sẽ là O(n). Bất lợi của mảng có thứ tự là quá trình chèn thêm phần tử có độ phức tạp O(n), bởi vì những phần tử có giá trị lớn hơn phải di chuyển để chứa phần tử mới. Việc chèn thêm phần tử của mảng có thứ tự có thời gian cố định là O(1).

32. Những cách làm tốt nhất (best practices) liên quan đến  Collection trong Java?

  • Chọn loại collection phù hợp để sử dụng, dựa vào ứng dụng đang cần gì, và cốt yếu là hiệu năng (performance) khi sử dụng nó. Ví dụ, nếu kích cỡ của các phẩn tử là cố định và biết trước, chúng ta nên sử dụng Array thay vì ArrayList.
  • Một số lớp collection cho phép chúng ta đưa vào sức chứa khi khởi tạo (initial capacity). Vì vậy, nếu chúng ta ước lượng số lượng phần tử mà muốn lưu trữ, chúng ta có thể sử dụng nó (capacity) để tránh việc làm mới hay thay đổi kích thước mảng.
  • Luôn luôn sử dụng Generics cho các kiểu dữ liệu an toàn(type-safety), dễ đọc và tinh tế hơn. Ngoài ra, sử dụng Generics, bạn tránh được ClassCastException trong quá trình thực thi (runtime).
  • Sử dụng lớp bất biến(immutable classes) được cung cấp bởi JDK như khóa trong Map, để tránh việc cài đặt hàm hashCode và equals cho những lớp tự mình tùy chỉnh.
  • Program in terms of interface not implementation (Không biết dịch thế nào :D, sẽ cố gắng giải thích trong chú thích riêng)
  • Trả về một tập hợp hay mảng rỗng thay vì trả về giá trị null trong trường hợp collection thật sự rỗng.

33. Sự khác biệt giữa hai interfaces Enumeration và Iterator?

Enumeration nhanh gấp đôi so với Iterator và sử dụng rất ít bộ nhớ. Tuy nhiên, Iterator an toàn hơn Enumeration, bởi vì những thread ( luồng) khác không thể thay đổi đối tượng collection khi đang duyệt qua bởi Iterator. Ngoài ra, Iterator cho phép loại bỏ phần từ trong tập hợp, trong khi không thể làm điều đó với Enumeration.

34. Sự khác biệt giữa HashSet và TreeSet?

HashSet được cài đặt sử dụng bảng băm (hash table), nên những phần tử của nó không có thứ tự. Các phương thức add, remove và contains của HashSet có độ phức tạp là O(1). TreeSet được cài đặt sử dụng cấu trúc cây (tree structure). Những phần tử trong TreeSet được sắp xếp, nên các phương thức add, remove và contains có độ phức tạp O(logn).

GARBAGE COLLECTORS

35. Mục đích của bộ dọn rác (Garbage collection) trong Java là gì, và khi nào thì nó được sử dụng?

Mục đích của bộ dọn rác là để xác định và loại bỏ những đối tượng nào không còn cần thiết trong ứng dụng, để cho tài nguyên được tái sử dụng.

36. System.gc() và Runtime.gc() làm gì?

Những phương thức này có thể được sử dụng như một lời gợi ý đối với JVM, để khởi động một bộ dọn rác. Tuy nhiên, điều đó tùy vào JVM sẽ khởi động bộ dọn rác ngay lập tức hay đợi một thời gian sau.

37. Khi nào thì finalize() được gọi? Mục địch của finalization là gì?

Phương thức finalize được gọi bởi bộ dọn rác (garbage collector), trước khi giải phóng vùng nhớ của đối tượng. Thông thường, nó được gọi để giải phóng tài nguyên được giữ bởi đối tượng bên trong phương thức finalize.

38. Nếu một đối tượng được gán là null, có phải bộ dọn rác sẽ giải phóng vùng nhớ của đối tượng ngay tức khắc không?

Không, đối tượng đó sẽ vẫn được giữ trong bộ dọn rác đến lần dọn rác tiếp theo của bộ dọn rác.

39. Cấu trúc của Heap trong Java là gì? Thế nào là Perm Gem trong Heap?

Heap là vùng dữ liệu khi chương trình thực thi, vùng nhớ dành cho tất cả các lớp và mảng được cấp phát. Nó (heap) được khởi tạo khi JVM khởi động. Vùng nhớ heap được giải phóng bởi hệ thống quản lý bộ nhớ tự động, chính là bộ dọn rác (garbage collector). Vùng nhớ heap chứa cả đối tượng sống (live) và dead(chết). Những đối tượng sống (live) còn được truy cập bởi ứng dụng và sẽ không bị lệ thuộc vào bộ dọn rác. Những đối tượng chết(dead) là những đối tượng sẽ không giờ được truy xuất từ ứng dụng, nhưng chưa bao giờ được thu thập từ bộ dọn rác. Những đối tượng này vẫn chiếm giữ bộ nhớ đến khi một sự kiện dọn rác xảy ra.

40. Sự khác nhau giữa bộ dọn rác Serial và Throughput?

Bộ dọn rác throughput sử dụng tính toán song song của bộ dọn young generation và vì vậy nó được sử dụng trong những ứng dụng có bộ dữ liệu vừa và lớn. Còn bộ dọn Serial phù hợp với những ứng dụng nhỏ.

41. Khi nào thì một đối tượng trở thành đối tượng phù hợp vào bộ dọn rác?

Khi đối tượng không còn truy cập từ chương trình mà nó đang được sử dụng.

42. Có phải quá trình dọn rác xảy ra trong vùng Permanent Generation(PermGen) trong JVM không?

Bộ dọn rác xảy ra trong vùng PermGen và nếu PermGen đầy hay vượt ngưỡng, nó có thể gây nên đầy bộ dọn rác. Nếu bạn nhìn kỹ vào output(xuất) của bộ dọn rác, bạn sẽ thấy là PermGen cũng là bộ dọn rác. Đó là lý do tại sao phải nhập đúng dung lượng của PermGen để tránh xảy ra đầy bộ dọn rác.

EXCEPTION HANDLING

43. Hai loại exception(ngoại lệ) trong java là gì? Điểm khác biệt của chúng?

Java có 2 loại exception: checked exception và unchecked exception. Unchecked exception không cần phải khai báo trong hàm hay trong hàm khởi tạo ném ra loại lệ, nếu chúng có thể bị ném ra bởi một exception trong hàm hay hàm khởi tạo, thì sẽ truyền ra ngoài hàm hay hàm khởi tạo gọi chúng. Checked exception phải được khai báo bên trong hàm hoặc hàm khởi tạo. Xem thêm về Java Exception.

44. Sự khác nhau giữa Exception và Error trong Java là gì?

2 lớp Exception và Error đều là subclass(lớp con) của lớp Throwable. Lớp Exception được sử dụng cho ngoại lệ có điều kiện mà chương trình nên bắt. Lớp Error định nghĩa các ngoại lệ mà không thể bắt (catch) từ chương trình.

45. Sự khác nhau giữa throw và throws?

Từ khóa throw được sử dụng tường minh để tạo (raise) ngoại lệ trong chương trình. Còn throws được sử dụng để biểu thị những exception không được xử lý bởi hàm. Mỗi hàm phải chỉ ra được exception nào không được xử lý, vì vậy người gọi hàm đó có thể bảo vệ nó dựa vào các exception có thể xảy ra. Cuối cùng, nhiều exception được ngăn cách bằng dấu , (comma).

45. Khối Finally trong Exception quan trọng thế nào?

Khối finally sẽ luôn luôn được chạy (execute) cho dù exception có xảy ra hay không. Ngay trong trường hợp khối lệnh catch bị bỏ qua và exception ném ra trong khối đó, khối lệnh finally vẫn sẽ được thực thi. Điều cuối cùng được đề cập về khối lệnh finally, nó được sử dụng để giải phóng tài nguyên như I/O buffers, database connection (kết nối cơ sở dư liệu), v.v..

46. Chuyện gì xảy ra với đối tượng Exception sau khi exception được sử lý?

Đối tượng Exception sẽ được bộ dọn rác xóa trong chu kỳ dọn rác tiếp theo của nó.

47. Hàm finalize() và khối finally khác nhau như thế nào?

Khối lệnh finally sẽ được thự thi cho dù exception có xảy ra hay không và được sử dụng để giải phóng tài nguyên bị giữ bỏi ứng dụng. Fianlize là một hàm protected (modifier) của lớp Object, được gọi bởi JVM trước khi đối tượng đó được xử lý bởi bộ dọn rác.

 

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s