Câu hỏi phỏng vấn JavaCore Phần 3
Hôm nay, Freetuts tiếp tục Series của những bộ câu hỏi phỏng vấn Java: Trong phần này mình sẽ tập trung các câu hỏi về cấu trúc Java căn bản .....
Java là gì? Điểm khác biệt chính giữa Java và các ngôn ngữ lập trình khác là gì?
Java là một ngôn ngữ lập trình đa năng và phổ biến được sử dụng rộng rãi trong các ứng dụng máy tính, ứng dụng web, di động và các hệ thống phân tán.
Điểm khác biệt chính giữa Java và các ngôn ngữ lập trình khác là:
- Java được biên dịch thành bytecode và chạy trên máy ảo Java (JVM), cho phép nó có khả năng di động trên nhiều nền tảng khác nhau.
- Java là một ngôn ngữ lập trình hướng đối tượng, có tính năng quản lý bộ nhớ tự động, cấu trúc rõ ràng và mã nguồn có thể đọc được.
Java có bao nhiêu kiểu dữ liệu?
Các kiểu dữ liệu nguyên thủy (primitive data types) trong Java bao gồm:
- Kiểu số nguyên: byte, short, int, long
- Kiểu số thực: float, double
- Kiểu ký tự: char
- Kiểu boolean: boolean
Các kiểu dữ liệu đối tượng (object data types) trong Java bao gồm:
- Kiểu String
- Kiểu mảng (array)
- Kiểu đối tượng (object)
Sự khác biệt giữa array và ArrayList là gì?
Dưới đây là bảng so sánh sự khác nhau giữa mảng (array) và ArrayList trong Java:
Bài viết này được đăng tại [free tuts .net]
Mảng (array) |
ArrayList |
Có kích thước cố định |
Có thể thay đổi kích thước |
Có thể lưu trữ các phần tử cùng kiểu dữ liệu |
Có thể lưu trữ các phần tử cùng hoặc khác kiểu dữ liệu |
Không có phương thức để thêm hoặc xóa phần tử |
Có phương thức để thêm, xóa, sửa phần tử |
Không thể sử dụng vòng lặp for-each |
Có thể sử dụng vòng lặp for-each |
Được xử lý bởi máy ảo Java (JVM) |
Được xử lý bởi thư viện Java |
Dễ dàng truy cập vào phần tử bằng chỉ mục |
Điểm yếu trong việc truy cập ngẫu nhiên vì phải dùng phương thức get() hoặc iterator() |
Có thể lưu trữ các giá trị nguyên thuỷ và đối tượng |
Chỉ lưu trữ các đối tượng |
Có thể truy cập trực tiếp đến phần tử đầu tiên và cuối cùng |
Có thể truy cập đến phần tử đầu tiên và cuối cùng thông qua phương thức get() và size() |
Ví dụ: Đây là hai ví dụ rõ ràng nhất
Mảng:
int[] numbers = {1, 2, 3, 4, 5}; System.out.println(numbers[2]); // Output: 3
ArrayList:
//Cùng Freetuts học lập trình ArrayList<String> names = new ArrayList<>(); names.add("John"); names.add("Mary"); System.out.println(names.get(1)); // Output: Mary
Điểm khác biệt giữa Interface và Abstract Class là gì?
Dưới đây là bảng so sánh giữa Interface và Abstract Class:
Interface |
Abstract Class |
Chỉ chứa phương thức trừu tượng hoặc mặc định (default methods). |
Có thể chứa cả phương thức trừu tượng và phương thức thực thi (concrete methods). |
Không có hàm khởi tạo (constructor). |
Có thể có hàm khởi tạo. |
Cho phép tính đa kế thừa. |
Chỉ cho phép kế thừa từ một Abstract Class duy nhất. |
Không chứa biến ngoài các biến hằng (constant). |
Có thể chứa các biến khác. |
Thường được sử dụng để định nghĩa các hành vi, chức năng, tương tác giữa các đối tượng. |
Thường được sử dụng để định nghĩa các thuộc tính và các phương thức trừu tượng liên quan đến lớp cha. |
Ví dụ:
// Interface interface Shape { void draw(); } // Abstract Class abstract class Polygon { protected int sides; public Polygon(int sides) { this.sides = sides; } public abstract double getArea(); public abstract double getPerimeter(); public void displaySides() { System.out.println("This polygon has " + sides + " sides."); } }
Trong ví dụ trên, interface "Shape" chứa phương thức trừu tượng "draw" để định nghĩa hành vi vẽ hình dạng. Trong khi đó, Abstract Class "Polygon" chứa các thuộc tính và phương thức trừu tượng "getArea" và "getPerimeter" để tính diện tích và chu vi, và phương thức thực thi "displaySides" để hiển thị số lượng cạnh của đa giác. Ở đây, Interface được sử dụng để định nghĩa hành vi của hình dạng, trong khi Abstract Class được sử dụng để định nghĩa các thuộc tính và phương thức chung của đa giác.
Có bao nhiêu loại Exception trong Java? Hãy đưa ra ví dụ về mỗi loại Exception.
Trong Java, có hai loại Exception: Checked Exception
và Unchecked Exception
.
Checked Exception:
- Là các Exception được kiểm tra bởi trình biên dịch và phải được bắt hoặc ném (throw) trong khối try-catch hoặc khai báo ra ngoài phương thức (throws).
- Checked Exception thường xảy ra trong các trường hợp bất thường có thể xảy ra như không tìm thấy file, kết nối cơ sở dữ liệu thất bại, lỗi định dạng dữ liệu, v.v.
Ví dụ:
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class FileReaderExample { public static void main(String[] args) { try { FileReader fileReader = new FileReader("input.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader); String line = bufferedReader.readLine(); System.out.println(line); bufferedReader.close(); } catch (FileNotFoundException e) { System.out.println("File not found: " + e.getMessage()); } catch (IOException e) { System.out.println("Error reading file: " + e.getMessage()); } } }
Trong ví dụ này, chúng ta đang cố gắng đọc một tập tin bằng cách sử dụng đối tượng FileReader và BufferedReader. Tuy nhiên, các phương thức này đều có thể ném ra các ngoại lệ kiểu IOException, là một loại Checked Exception, do vậy chúng ta phải bao quanh các câu lệnh này trong khối try-catch để xử lý ngoại lệ.
Nếu không xử lý ngoại lệ này, chương trình sẽ không biên dịch được và sẽ hiển thị một thông báo lỗi tại dòng có ngoại lệ, ví dụ như sau:
Unhandled exception type IOException
Điều này cho thấy rằng Checked Exception là các ngoại lệ phải được xử lý hoặc khai báo để tránh lỗi biên dịch.
Unchecked Exception:
- Là các Exception không được kiểm tra bởi trình biên dịch và có thể xảy ra trong quá trình thực thi chương trình.
- Unchecked Exception thường xảy ra trong các trường hợp như chia cho số 0, truy cập mảng vượt quá chỉ số, null pointer, v.v.
Ví dụ:
public class DivideByZeroExample { public static void main(String[] args) { int a = 10; int b = 0; int result; try { result = a / b; } catch (ArithmeticException e) { System.out.println("Error: " + e.getMessage()); } } }
Trong ví dụ này, chúng ta đang cố gắng chia một số nguyên cho số không bằng cách thực hiện phép chia a / b. Tuy nhiên, chương trình sẽ ném ra ngoại lệ kiểu ArithmeticException khi chúng ta cố gắng chia một số cho số không.
Điều đặc biệt ở đây là ArithmeticException là một Unchecked Exception, có nghĩa là chúng ta không bắt buộc phải xử lý nó hoặc khai báo nó trong khối try-catch. Tuy nhiên, nếu không xử lý ngoại lệ này, chương trình sẽ bị dừng lại và hiển thị một thông báo lỗi trên console.
Vì vậy, để tránh những tình huống không mong muốn khi sử dụng Unchecked Exception, chúng ta nên đảm bảo rằng các phép tính trong chương trình của mình sẽ không bị chia cho số không, tránh việc ném ra các ngoại lệ không kiểm soát được.
Phân biệt “throw” và “throws” trong java?
Trong Java, "throw" và "throws" là hai khái niệm khác nhau và thường được sử dụng trong quá trình xử lý ngoại lệ.
Ví dụ: "throw" là một lệnh được sử dụng để tạo ra một ngoại lệ mới trong một phương thức hoặc khối mã, để báo hiệu rằng một lỗi đã xảy ra. Lệnh "throw" phải được sử dụng bên trong một khối "try-catch" hoặc phải khai báo ngoại lệ đó bằng từ khóa "throws".
//Học lập trình cùng Freetuts public class Main { public void divide(int a, int b) throws ArithmeticException{ if(b == 0) throw new ArithmeticException("Không thể chia cho 0"); int result = a/b; System.out.println("Result: " + result); } }
Trong ví dụ trên, nếu biến b bằng 0, phương thức sẽ tạo ra một ngoại lệ "ArithmeticException" bằng lệnh "throw" để báo hiệu rằng không thể chia một số cho 0.
Ví dụ: "throws" là một từ khóa được sử dụng để khai báo các ngoại lệ mà phương thức có thể ném ra. Khai báo "throws" phải được thực hiện trong phần khai báo phương thức và sử dụng để báo hiệu cho người dùng của phương thức biết về các ngoại lệ mà phương thức có thể ném ra.
//Học lập trình cùng Freetuts import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Main { public void readFile(String fileName) throws IOException{ BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(fileName)); String line = reader.readLine(); while(line != null){ System.out.println(line); line = reader.readLine(); } }catch (IOException e) { throw e; }finally { if (reader != null){ reader.close(); } } } }
Trong ví dụ trên, phương thức "readFile" khai báo "throws IOException" để báo hiệu cho người dùng phương thức biết rằng phương thức có thể ném ra ngoại lệ "IOException". Ngoại lệ này có thể xảy ra khi đọc tập tin và phương thức ném lại ngoại lệ đó bằng lệnh "throw" bên trong khối "catch".
Điểm khác biệt giữa StringBuffer và StringBuilder là gì? Khi nào bạn nên sử dụng một trong số chúng?
StringBuffer và StringBuilder đều là lớp được sử dụng để thao tác trên chuỗi trong Java. Tuy nhiên, điểm khác biệt chính giữa chúng là tính đồng bộ (synchronized) và hiệu suất.
- StringBuffer là lớp được đồng bộ hóa, nghĩa là nó được thiết kế để đảm bảo tính an toàn đối với đa luồng (thread-safe). Điều này đảm bảo rằng nhiều luồng không thể truy cập vào đối tượng StringBuffer cùng một lúc. Mỗi phương thức của StringBuffer đều được đồng bộ hóa, do đó, việc sử dụng StringBuffer sẽ chậm hơn so với StringBuilder khi chỉ sử dụng trong một luồng duy nhất.
- StringBuilder là lớp không đồng bộ, do đó, nó không được thiết kế để đảm bảo tính an toàn đối với đa luồng (non-thread-safe). Vì vậy, việc sử dụng StringBuilder trong nhiều luồng có thể gây ra các vấn đề đồng bộ hóa. Tuy nhiên, do không phải đồng bộ hóa, nên StringBuilder có hiệu suất tốt hơn so với StringBuffer.
Khi sử dụng một trong hai lớp StringBuffer và StringBuilder, cần cân nhắc sử dụng đồng bộ (synchronized) và hiệu suất để quyết định lớp nào phù hợp hơn trong một tình huống cụ thể.
Ví dụ về việc sử dụng StringBuffer trong một phương thức đồng bộ:
//Học lập trình cùng Freetuts public class Main { public synchronized void appendText(String text){ StringBuffer sb = new StringBuffer(); sb.append(text); System.out.println(sb.toString()); } }
Ví dụ về việc sử dụng StringBuilder khi không cần đồng bộ:
//Học lập trình cùng Freetuts public class Main { public void appendText(String text){ StringBuffer sb = new StringBuffer(); sb.append(text); System.out.println(sb.toString()); } }
Trên là những câu hỏi phỏng vấn về Java cơ bản phần 2, bài này mình xin dừng ở đây, hẹn gặp lại các bạn ở bài tiếp theo.