Câu hỏi phỏng vấn JavaCore phần 2
Để giúp bạn có thể chuẩn bị tốt nhất, hôm nay freetuts sẽ tiếp tục series các câu hỏi phỏng vấn JavaCore. Dưới đây là những câu hỏi thường gặp khi bạn đi phỏng vấn JavaCore.
Câu 1: Hãy trình bày hiểu biết của bạn về JVM, JRE, JDK?
-
JVM, JRE và JDK là các khái niệm liên quan đến Java và môi trường thực thi Java.
-
JVM (Java Virtual Machine):
JVM là một máy ảo Java, là thành phần chính của Java Runtime Environment (JRE). JVM được sử dụng để thực thi mã Java, nó chuyển đổi mã Java được viết bằng ngôn ngữ Java thành mã máy được hiểu bởi hệ điều hành. JVM có thể chạy trên nhiều nền tảng khác nhau như Windows, Linux, Mac, v.v.
-
JRE (Java Runtime Environment):
JRE bao gồm JVM và các thư viện Java cần thiết để thực thi các ứng dụng Java. JRE được sử dụng để chạy các ứng dụng Java trên máy tính. Nó cung cấp môi trường thực thi cho các ứng dụng Java.
-
JDK (Java Development Kit):
JDK là bộ công cụ phát triển Java, bao gồm JRE và các công cụ cần thiết để phát triển ứng dụng Java, bao gồm trình biên dịch Java (javac), trình tạo JAR (jar), trình quản lý gói (pkgmgr), v.v. JDK cung cấp môi trường phát triển hoàn chỉnh để phát triển các ứng dụng Java.
Bài viết này được đăng tại [free tuts .net]
Câu 2: Tại sao Java được gọi là “Write once, run anywhere” ?
-
Java được gọi là "write once, run anywhere" bởi vì ngôn ngữ lập trình Java cho phép người lập trình viết mã chỉ một lần và chạy trên nhiều nền tảng khác nhau mà không cần thay đổi mã nguồn.
Giải thích:
-
JVM cung cấp một môi trường thực thi độc lập với hệ điều hành và phần cứng.
-
Khi bạn viết mã Java, mã đó được biên dịch thành bytecode, một ngôn ngữ trung gian được hiểu bởi JVM. Khi chạy chương trình, JVM sẽ biên dịch bytecode thành mã máy thích hợp cho nền tảng đang chạy. Do đó, chương trình Java có thể chạy trên bất kỳ hệ điều hành nào có JVM tương ứng.
-
Điều này giúp tiết kiệm thời gian và công sức cho các lập trình viên, vì họ không cần phải viết mã khác nhau cho từng nền tảng. Nó cũng giúp đơn giản hóa việc phát triển và bảo trì ứng dụng, vì chỉ cần phát triển và kiểm thử trên một nền tảng và sau đó chạy trên nhiều nền tảng khác nhau mà không cần chỉnh sửa lại mã nguồn.
Câu 3: So sánh sự khác nhau giữa int và Integer trong Java?
Để dễ hình dung thì chúng ta có bảng sau:
int |
Integer |
Là kiểu dữ liệu nguyên thủy |
Là một lớp trong Java |
Không thể được gán giá trị null |
Có thể null |
Sử dụng để lưu trữ giá trị số nguyên |
Sử dụng để lưu trữ giá trị số nguyên |
Có giá trị mặc định là 0 |
Có giá trị mặc định là null |
Thực hiện các phép toán số học trực tiếp |
Để thực hiện các phép toán số học cần phải sử dụng phương thức của lớp Integer |
Có thể sử dụng trong các cấu trúc điều khiển, ví dụ như switch case |
Cần phải sử dụng phương thức intValue() để chuyển đổi thành kiểu dữ liệu nguyên thủy để sử dụng trong các cấu trúc điều khiển |
Sử dụng ít bộ nhớ |
Sử dụng nhiều bộ nhớ hơn so với int do nó là một lớp và bao gồm các phương thức và thông tin phụ |
Không thể sử dụng các cấu trúc dữ liệu yêu cầu đối tượng như ArrayList |
Có thể sử dụng được các cấu trúc dữ liệu yêu cầu đối tượng. |
Câu 4: So sánh bộ nhớ Stack và Heap?
-
Bộ nhớ Stack (hay còn gọi là ngăn xếp) là một vùng nhớ trong máy tính được sử dụng để lưu trữ các biến cục bộ và tham số của hàm trong quá trình thực thi của một chương trình. Khi một hàm được gọi, các tham số và biến cục bộ của hàm đó được lưu trữ trên bộ nhớ Stack và khi hàm đó hoàn thành thì các giá trị này sẽ bị xóa khỏi bộ nhớ Stack.
-
Bộ nhớ Heap là một vùng nhớ trong máy tính được sử dụng để lưu trữ các đối tượng và mảng trong quá trình thực thi của một chương trình. Khi một đối tượng được tạo ra, nó được lưu trữ trên bộ nhớ Heap và khi không còn được sử dụng thì được giải phóng để tránh lãng phí tài nguyên bộ nhớ.
Dưới đây là bảng so sánh sự khác nhau giữa 2 bộ nhớ trên.
Bộ nhớ Stack |
Bộ nhớ Heap |
|
Mục đích |
Lưu trữ các biến cục bộ và tham số của các hàm trong quá trình thực thi |
Lưu trữ các đối tượng và mảng trong quá trình thực thi |
Quản lý |
Được quản lí bởi Hệ điều hành |
Được quản lý bởi trình quản lý bộ nhớ JVM |
Tổ chức |
Tổ chức theo cơ chế ngăn xếp(LIFO) |
Tổ chức theo cơ chế bảng điểm(hash table) |
Số lượng |
nhỏ hơn |
lớn hơn |
Thời gian sống |
Thời gian sống của các biến cục bộ và tham số của hàm ngắn hơn thời gian sống của các đối tượng trên Heap |
Thời gian sống của các đối tượng Heap dài hơn thời gian sống của các biến cục bộ |
Cơ chế giải phóng |
Tự động giải phóng khi hàm thực thi hoàn tất |
Được giải phóng bởi trình quản lý bộ nhớ khi không còn được tham chiếu |
(Việc hiểu rõ sự khác nhau giữa hai loại bộ nhớ này rất quan trọng đối với các lập trình viên Java để tối ưu hóa sử dụng tài nguyên bộ nhớ của chương trình.)
Câu 5: Hãy trình bày hiểu biết về tính đa hình trong lập trình hướng đối tượng.
-
Khái niệm: Tính đa hình (Polymorphism) là một khái niệm trong lập trình hướng đối tượng mô tả khả năng của đối tượng để có thể hiểu và đáp ứng các yêu cầu khác nhau của chương trình một cách linh hoạt.
-
Vai trò của tính đa hình:
-
Cho phép các đối tượng của các lớp khác nhau sử dụng một phương thức hoặc gọi một phương thức cùng tên nhưng có tham số và giá trị trả về khác nhau để thực hiện một hành động tương tự.
/** * học lập trình cùng Freetuts * Freetuts.net */ class Animal{ public void makeSound(){ System.out.println("The animal makes a sound"); } } class Cat extends Animal{ public void makeSound(){ System.out.println("Meow"); } } class Dog extends Animal{ public void makeSound(){ System.out.println("Woof"); } } public class Main { public static void main(String[] args) { Animal myPet = new Cat(); myPet.makeSound();// prints Meow myPet = new Dog(); myPet.makeSound(); // prints Woof } }
-
Tính đa hình giúp cho việc lập trình trở nên dễ dàng hơn và linh hoạt hơn. Nó cho phép lập trình viên tái sử dụng lại mã nguồn, giảm thiểu lượng mã phức tạp và dễ dàng bảo trì các chương trình.
-
Tính đa hình cho phép các đối tượng có thể được truy cập thông qua các giao diện chung, giúp cho việc phát triển và sử dụng các thư viện và khung làm việc trở nên dễ dàng hơn.
-
Nhược điểm của tính đa hình:
-
Khó triển khai : Khi sử dụng tính đa hình, người đọc và người sử dụng mã có thể gặp khó khăn trong việc hiểu hoạt động của chương trình, vì các phương thức có thể có các hành vi khác nhau với cùng một tên.
-
Không đảm bảo kiểm tra lỗi tại thời điểm biên dịch: Vì các phương thức được gọi động tại thời điểm chạy, nên các lỗi được phát hiện tại thời điểm chạy chương trình, chứ không phải tại thời điểm biên dịch.
-
Không phù hợp với các hệ thống lớn và phức tạp: Khi sử dụng tính đa hình trong các hệ thống lớn và phức tạp, có thể dẫn đến việc các phương thức bị lỗi hoặc xung đột, do đó cần có sự kiểm soát cẩn thận khi thiết kế và triển khai hệ thống.
-
Yêu cầu cấu trúc phức tạp: Tính đa hình có thể yêu cầu cấu trúc phức tạp để thực hiện, ví dụ như phải sử dụng các giao diện và lớp trừu tượng, đòi hỏi sự hiểu biết chuyên sâu về lập trình hướng đối tượng.
-
Phân loại: Đa hình được chia thành 2 loại là Overloading và Overriding
Freetuts đã viết một bài phân tích về 2 loại đa hình trên ở link này:
Overriding và Overloading trong Java.
Câu 6: Phân biệt ArrayList và LinkedList
-
Khái niệm:
-
ArrayList là một danh sách động (dynamic list), được triển khai dựa trên mảng (array) có kích thước thay đổi được.Các phần tử trong ArrayList được lưu trữ dưới dạng một mảng đối tượng, và khi số lượng phần tử trong danh sách thay đổi, kích thước của mảng cũng sẽ được điều chỉnh tương ứng.
-
LinkedList là một danh sách liên kết (linked list), được triển khai dựa trên cấu trúc các node liên kết với nhau. Mỗi node sẽ lưu trữ giá trị và một tham chiếu đến node kế tiếp trong danh sách.
Dưới đây là bảng so sánh giữa ArrayList và LinkedList:
Tính năng |
ArrayList |
LinkedList |
Cấu trúc dữ liệu |
Mảng |
Danh sách liên kết |
Thao tác truy cập |
O(1) |
O(n) |
Thao tác chèn, xóa |
O(n) |
O(1) |
Sử dụng bộ nhớ |
Tốn bộ nhớ cho mảng |
Không tốn bộ nhớ cho mảng |
Sử dụng tài nguyên |
Cần tài nguyên hơn nếu kích thước danh sách lớn |
Cần ít tài nguyên hơn nếu kích thước danh sách lớn |
Sử dụng trong trường hợp nào? |
Nên sử dụng khi cần thao tác truy cập nhiều hơn là chèn, xóa |
Nên sử dụng khi cần thao tác chèn, xóa phần tử nhiều hơn là truy cập |
Câu 7: Trình bày các đặc điểm của HashSet
-
Khái niệm: HashSet là một cấu trúc dữ liệu trong Java, được sử dụng để lưu trữ tập hợp các phần tử duy nhất (distinct elements).
-
Các đặc điểm chính của HashSet bao gồm:
-
Không cho phép phần tử trùng lặp: HashSet sử dụng thuật toán băm (hashing) để lưu trữ các phần tử. Mỗi phần tử sẽ được gán một giá trị băm (hash code) và được lưu trữ trong một vị trí tương ứng trong bảng băm (hash table). Với cùng một giá trị băm, các phần tử được so sánh với nhau bằng phương thức equals() để đảm bảo tính duy nhất của tập hợp.
-
Tốc độ truy cập nhanh: HashSet sử dụng cấu trúc bảng băm (hash table) để lưu trữ các phần tử. Vì vậy, việc truy cập các phần tử bất kỳ trong tập hợp có độ phức tạp gần như là O(1).
-
Không lưu trữ thứ tự các phần tử: Các phần tử trong HashSet không được lưu trữ theo thứ tự cụ thể. Khi duyệt các phần tử trong HashSet, thứ tự xuất hiện của chúng có thể khác nhau so với thứ tự được thêm vào ban đầu.
-
Cho phép null: HashSet cho phép lưu trữ phần tử null.
-
Có thể được sử dụng trong các thuật toán băm (hashing): HashSet cung cấp một cấu trúc dữ liệu tương đối đơn giản và linh hoạt, có thể được sử dụng trong các thuật toán băm để giải quyết các bài toán liên quan đến lưu trữ tập hợp phần tử duy nhất.
Dưới đây là một ví dụ cụ thể về đặc điểm của HashSet:
import java.util.HashSet; //Học lập trình cùng Freetuts public class HashSetExample { public static void main(String[] args) { //Khởi tạo một HashSet HashSet<String> set = new HashSet<>(); //Thêm các phần tử vào tập hợp set.add("apple"); set.add("banana"); set.add("orange"); set.add("kiwi"); set.add("pineapple"); //Đặt vào một phần tử trùng lặp set.add("banana"); //In ra tập hợp System.out.println("Tập hợp sau khi thêm các phần tử: " + set); //Truy cập một phần tử trong tập hợp String element = "kiwi"; if (set.contains(element)){ System.out.println(element + "có trong tập hợp"); } else { System.out.println(element + "không có trong tập hợp"); } //Xóa một phần tử trong tập hợp String toRemove = "orange"; set.remove(toRemove); System.out.println("Tập hợp sau khi xóa " + toRemove + ": " + set); //Lấy số phần tử trong tập hợp System.out.println("Số phần tử trong tập hợp: " + set.size()); //Kiểm tra tập hợp có trống hay không ? System.out.println("Tập hợp có trống hay không? " + set.isEmpty()); //Duyệt tất cả các phần tử trong tập hợp System.out.println("Duyệt tất cả các phần tử trong tập hợp: "); for (String s: set){ System.out.println(s); } } }
Kết quả của chương trình như sau:
Tập hợp sau khi thêm các phần tử: [banana, orange, apple, kiwi, pineapple] kiwi có trong tập hợp Tập hợp sau khi xóa orange: [banana, apple, kiwi, pineapple] Số phần tử trong tập hợp: 4 Tập hợp có trống hay không? false Duyệt tất cả các phần tử trong tập hợp: banana apple kiwi pineapple
Như vậy, ta có thể thấy rằng:
-
HashSet không cho phép lưu trữ các phần tử trùng lặp.
Trong ví dụ này, khi ta thêm phần tử "banana" vào HashSet lần thứ hai, phần tử này không được thêm vào tập hợp.
-
HashSet cho phép truy cập phần tử trong tập hợp với tốc độ O(1).
Khi ta kiểm tra xem phần tử "kiwi" có trong tập hợp hay không, chương trình có thể truy cập phần tử này trong thời gian rất ngắn.
-
HashSet không giữ thứ tự của các phần tử.
Trong ví dụ này, khi ta thêm các phần tử vào HashSet, thứ tự các phần tử được sắp xếp một cách ngẫu nhiên. Khi ta duyệt qua tất cả các phần tử trong HashSet, thứ tự của các phần tử được in ra theo thứ tự mà HashSet tự động xác định.
-
HashSet cho phép xóa phần tử trong tập hợp.
Khi ta xóa phần tử "orange" khỏi HashSet, phần tử này được loại bỏ khỏi tập hợp.
-
HashSet cho phép lấy số phần tử trong tập hợp với tốc độ O(1).
Trong ví dụ này, khi ta gọi phương thức size() để lấy số phần tử trong HashSet, phương thức này trả về kết quả ngay lập tức.
-
HashSet cung cấp phương thức isEmpty() để kiểm tra xem tập hợp có trống hay không. Khi tập hợp không chứa phần tử nào, phương thức này trả về giá trị true.
/**
* learning setup freetuts free
* Freetuts.net
*/
lớp Động vật{
public void makeSound(){
System.out.println("Con vật kêu");
}
}
lớp Mèo mở rộng Động vật{
public void makeSound(){
System.out.println("Meo meo");
}
}
lớp Chó mở rộng Động vật{
public void makeSound(){
System.out.println("Gâu");
}
}
lớp công khai Chính {
public static void main(String[] args) {
MyPet động vật = con mèo mới();
myPet.makeSound();// in Meow
myPet = Con chó mới();
myPet.makeSound(); // in Gâu
}
}
chèn file
bảng băm