Là một lập trình viên Java, chắc hẳn bạn đã học rất nhiều kiến thức vô cùng quan trọng để có thể thực hiện các dự án của mình và chuẩn bị cho công việc sau này. Tuy nhiên, liệu những câu hỏi phỏng vấn tại các công ty có giống với những gì bạn đã học.

Hãy cùng đọc bài viết sau của Frog và tìm hiểu các câu hỏi phỏng vấn Java thường gặp để chuẩn bị tốt nhất cho buổi phỏng vấn trong tương lai nhé!

I. Các câu hỏi Java core

JDK, JRE và JVM là gì?

JDK là viết tắt của Java Development Kit – Bộ công cụ phát triển Java. JDK là một bộ công cụ phát triển phần mềm được dùng để phát triển ứng dụng trong Java.

JRE là viết tắt của Java Runtime Environment – Môi trường thực thi Java.

JRE bao gồm JVM, thư viện và các thành phần bổ sung để chạy các ứng dụng viết bằng ngôn ngữ Java.

JVM là viết tắt của Java Virtual MachineMáy ảo Java.

JVM là máy ảo được sử dụng để chạy các chương trình Java.

Cách hoạt động của JVM: Khi chương trình Java được chạy, trình biên dịch sẽ dịch Java code thành bytecode và sau đó JVM sẽ thực hiện nhiệm vụ của mình: thông dịch bytecode thành mã máy cho máy tính thực hiện lệnh.

Đặc điểm nổi bật của Java 8

1. Lambda Expression

Lambda Expressionfeature nổi bật nhất của Java 8, giúp cho cú pháp của Java trở nên đơn giản, rút gọn đi rất nhiều

Ví dụ không dùng Lambda
package vn.viettuts.java8;
 
interface Drawable {
    public void draw();
}
 
public class LambdaExpressionExample1 {
    public static void main(String[] args) {
        int width = 10;
 
        // không sử dụng biểu thức lambda, 
        // phải sử dụng lớp nặc danh để cài đặt phương thức draw() cho Drawable
        Drawable d = new Drawable() {
            public void draw() {
                System.out.println("Drawing " + width);
            }
        };
        d.draw();
    }
}
// Kết quả: Drawing 10
Ví dụ Áp dụng Lambda
package vn.viettuts.java8;
 
//tùy chọn, nó đánh dấu lớp Drawable chỉ được có 1 method trừu tượng
@FunctionalInterface
interface Drawable {
    public void draw();
}
 
public class LambdaExpressionExample2 {
    public static void main(String[] args) {
        int width = 10;
 
        // sử dụng biểu thức lambda
        Drawable d2 = () -> {
            System.out.println("Drawing " + width);
        };
        d2.draw();
    }
}

// Kết quả: Drawing 10

2. Default method in Interface

Java 8 cho phép thêm các method không trừu tượng bằng cách thêm từ khóa default:

Ví dụ:

public interface Calculate {
  default int sum(int a, int b) {
    return a + b;
  }
}
class Calculator implements Calculate {
  public static void main(String[] args) {
    Calculator calculator = new Calculator();
    calculator.sum(1, 2); // return 3
  }
}

3. Optional Class

Tính năng Optional Class giúp giải quyết các vấn đề chủ yếu về nullpointer

  • Optional Class là 1 tính năng mới trong được bổ sung trong Java 8
  • Optional là 1 đối tượng generic, bản chất của Optional là một container (bao chứa) chứa đối tượng mà nó reference tới. Nó có thể rỗng hoặc chứa giá trị NULL (trường hợp đối tượng mà nó reference tới bị null).
  • Cấu trúc này đảm bảo các biến được sử dụng thông qua Optional Class sẽ tránh được lỗi NullPointerException.
No.Phương thức & mô tả
1static <T> Optional<T> empty()
Trả về một Optional instance rỗng.
2Optional<T> filter(Predicate<? super <T> predicate)
Nếu như có giá trị hiện diện trong đối tượng Optional này và giá trị của nó khớp với Predicate truyền vào, nó sẽ trả về một Optional chứa giá trị đó, mặc khác sẽ trả về một Optional rỗng.
3T get()
Nếu như có giá trị trong Optional này, nó sẽ trả về giá trị đó, ngược lại sẽ ném ra NoSuchElementException nếu như đối tượng rỗng.
4void ifPresent(Consumer<? super T> consumer) 
Nếu như đối tượng Optional đang chứa giá trị, nó sẽ áp dụng consumer được truyền vào cho giá trị của nó. Ngược lại thì không làm gì cả.
5boolean isPresent()
Phương thức này được sử dụng để kiểm tra xem trong đối tượng Optional có đang chứa giá trị hay không. Giá trị trả về là True nếu có giá trị và ngược lại trả về false.
8static <T> Optional<T> of(T value)
Trả về đối tượng Optional kiểu T chứa giá trị của value.
7static <T> Optional<T> ofNullable(T value)
Trả về một Optional chứa giá trị được truyền vào nếu khác null, ngược lại sẽ trả về một Optional rỗng.
8T orElse(T other)
Trả về giá trị của đối tượng Optional nếu có, ngược lại nó sẽ trả về đối tượng other mà bạn đã truyền vào phương thức này.
9T orElseGet(Supplier<? extends T> other)
Trả về giá trị nếu tồn tại, ngược lại nó sẽ gọi other mà bạn đã truyền vào sau đó trả về kết quả của Supplier.
10<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
Nếu như đối tượng Optional có giá trị tồn tại thì nó sẽ trả về giá trị đó, ngược lại sẽ ném ra một Exception do chúng ta định nghĩa bởi Supplier đã truyền vào.

4. Java Stream API

Stream là 1 lớp trừu tượng mới được giới thiệu trong Java 8 giúp ta giải quyết các bài toán về collections, array 1 cách tự nhiên hơn như thêm, sửa, xóa, lọc object…

  • Stream là 1 lớp trừu tượng mới được giới thiệu trong Java 8. Sử dụng Stream, bạn có thể xử lý dữ liệu 1 cách tự nhiên giống như các câu lệnh SQL. Ví dụ ta có câu SQL sau:
SELECT SUM(salary) FROM Employee

Câu lệnh trên tự động trả về tổng lương của tất cả Employee mà không cần phải thực hiện bất kì tính toán gì ở phía đầu cuối developer (bình thường thì sẽ SELECT tất cả các Employeesau đó dùng code Java để duyệt và tính tổng của tất cả Employee).

Tương tự vấn đề trên, khi sử dụng Collections trong Java, chúng ta thực hiện các vòng lặp và thực hiện lại các đoạn kiểm tra.

Giả sử muốn tính tổng lương của các employee có role = ‘Developer’ từ 1 danh sách chúng ta phải thực hiện lặp tất cả các phần tử, kiểm tra phần tử đó có role = ‘Developer’ rồi cộng lại. Trong khi nếu muốn xử lý chúng song song lại dễ gặp lỗi.

public static final String ROLE_DEVELOPER = "Developer";
public double sumSalaryOfDeveloper(List<Employee> listEmployee) {
  double sumSalary = 0;
  for (Employee emp : listEmployee) {
    if (emp.getRole().equals(ROLE_DEVELOPER)) {
      sumSalary += emp.getSalary();
    }
  }
  return sumSalary;
}

Để giải quyết vấn đề đó, Java 8 giới thiệu Stream API giúp developer xử lý dữ liệu khai báo và tận dụng kiến trúc đa lõi (multicore) mà không cần viết mã cụ thể cho nó.

public static final String ROLE_DEVELOPER = "Developer";
public double sumSalaryOfDeveloper(List<Employee> listEmployee) {
  return listEmployee
  			.stream()
			.filter(p -> p.getRole().equals(ROLE_DEVELOPER))
			.mapToDouble(p -> p.getSalary()).sum();
}

Như vậy, bạn có thể hiểu stream đại diện cho một collection được xử lý tuần tự và hỗ trợ rất nhiều loại operation để tính toán dựa trên những element của collection đó (tính tổng, convert sang map, …)

5. Functional Interface

Phần này sẽ giải thích rõ tại sao cú pháp Lambda Expression lại được viết như thế.

Sẽ bổ sung sau

6. Java Date Time API

Sẽ bổ sung sau

Giải thích phương thức main() trong chương trình Java

Phương thức main() trong chương trình Java chính là điểm thực thi của chương trình, hay còn là điểm vào (entry point) khi thực hiện một xử lý trong chương trình Java.

Phương thức main() kết thúc là khi chương trình kết thúc và phương thức main() là điều kiện để cho các phương thức khác có thể thực thi.

Tại sao không sử dụng con trỏ trong Java?

Con trỏ pointer không được sử dụng trong Java vì con trỏ khá phức tạp và không an toàn.

Tại sao Java lại độc lập nền tảng?

Java độc lập nền tảng là do Java sử dụng JVM, máy ảo Java cung cấp cách thực thi mã Java độc lập với nền tảng.

Package trong Java là gì? Liệt kê những ưu điểm của các package

Package trong Java là một nhóm các lớp (class), giao diện (interface) và các package con tương tự.

Package thường được chia thành 2 loại:

  • Package được dựng sẵn
  • Package do người dùng định nghĩa

Ưu điểm của các package:

  • Tổ chức file (class, interface) theo một hệ thống để dễ dàng phân loại file.
  • Phân quyền truy cập giúp xem các class thuộc package nào khi được gọi ở phần access modifier.
  • Dễ dàng chọn lọc khi import.
    • Dùng lệnh import java.sql khi import tất cả các class.
    • Dùng lệnh import.util.regex khi sử dụng class nằm trong package regex.

Khác biệt giữa bộ nhớ Stack và Heap

Về kích thước vùng nhớ

  • Bộ nhớ Stack: có kích thước cố định tùy thuộc vào hệ điều hành
  • Bộ nhớ Heap: có kích thước không cố định, có thể tăng giảm tùy thuộc vào nhu cầu

Về đặc điểm vùng nhớ

  • Bộ nhớ Stack: Vùng nhớ được quản lý bằng hệ điều hành, dữ liệu được lưu sẽ tự động hủy sau khi hàm thực hiện xong nhiệm vụ của mình.
  • Bộ nhớ Heap: Vùng nhớ được quản lý bằng lập trình viên và các dữ liệu sẽ không bị hủy sau khi hàm thực hiện xong và lập trình viên phải tự hủy vùng nhớ.

Lỗi xảy ra với vùng nhớ

  • Bộ nhớ Stack: Có khả năng vượt quá dung lượng lưu trữ vì dung lượng bộ nhớ Stack chỉ có hạn.
  • Bộ nhớ Heap: Cũng có khả năng tràn vùng nhớ nếu bạn liên tục cấp phát vùng nhớ mà không giải phóng thường xuyên.

Hãy nêu sự khác biệt giữa biến local và biến instance

Biến local

  • Được khai báo trong hàm contructor, trong block hoặc trong các phương thức
  • Được tạo trong các phương thức, contructorblock. Bị phá hủy khi kết thúc phương thức, contructorblock.
  • Được lưu trên vùng nhớ stack
  • Không được sử dụng access modifier khi khai báo
  • Cần khởi tạo giá trị mặc định trước khi sử dụng

Biến instance

  • Được khai báo trong một lớp, ngoài phương thức, contructorblock
  • Được lưu trong bộ nhớ heap
  • Được tạo khi tạo đối tượng bằng nút new và bị phá hủy khi đối tượng bị phá hủy
  • Được sử dụng bởi phương thức, contructor, block, tuy nhiên phải được sử dụng qua một đối tượng cụ thể
  • Giá trị mặc định phụ thuộc vào kiểu dữ liệu
  • Có thể gọi trực tiếp bằng tên khi sử dụng trong class

Từ khóa final trong Java là gì?

Từ khóa final trong Java là từ khóa được dùng để hạn chế số lượng người dùng.

Lập trình viên có thể sử dụng ở nhiều ngữ cảnh: phương thức method, biến variable, lớp class.

Final là thuộc tính mà chúng sẽ không thể thay đổi giá trị. Các phương thức final không thể overide ở lớp con và các class final không thể kế thừa.

Từ khóa static trong Java là gì?

Static trong Java là từ khóa dùng để quản lý bộ nhớ và truy cập trực tiếp thông qua lớp khi không cần khởi tạo.

Từ khóa super trong Java

Super trong Java là một biến tham chiếu, dùng để tham chiếu đến đối tượng của lớp cha gần nhất một cách trực tiếp.

Mô tả sự khác biệt giữa String, StringBuilder và StringBuffer

  • String không thể thay đổi và không thể có class con
  • StringBufferStringBuilder có thể thay đổi được
  • StringBufferStringBuilder giống nhau, chỉ có điểm khác biệt khi sử dụng đa luồng
  • Về tốc độ xử lý: StringBuilder là tốt nhất sau đó đến StringBuffer và String.

Constructors trong Java là gì?

Constructors (Hàm ảo) trong Java là một phương thức được sử dụng để khởi tạo, trả về các đối tượng của lớp.

Thông thường, một Constructors sẽ trùng tên với lớp mà nó được định nghĩa.

Các lớp wrapper trong Java là gì?

Lớp wrapper trong Java là lớp đóng gói các kiểu, cung cấp cơ chế chuyển đổi dữ liệu nguyên thủy trở thành kiểu đối tượng, và ngược lại. .

Đọc bài viết sau để rõ hơn về các kiểu dữ liệu

Có bắt buộc phải khai báo constructor trong lớp?

Không bắt buộc phải khai báo constructor trong lớp. Nếu không khai báo, lớp sẽ dùng default constructor.

Các loại phạm vi truy cập trong Java

Có 4 phạm vi truy cập trong Java là public, private, default và protected.

  • Public: Có thể truy cập mọi lúc mọi nơi
  • Private: Chỉ có thể truy cập bên trong lớp
  • Default: Có thể truy cập từ trong lớp khai báo, các lớp cùng một gói với lớp khai báo
  • Protected: Có thể truy cập trong lớp khai báo, các lớp con của lớp khai báo, các lớp cùng một gói với lớp khai báo

Trình biên dịch JIT trong Java

Trình biên dịch JIT trong Java hay còn được biết đến với tên gọi Just-In-Time – là một kỹ thuật biên dịch các phần mã byte có các chức năng tương tự trong cùng một thời gian, qua đó giảm thời gian biên dịch cần thiết.

Mô tả khác biệt giữa constructor và phương thức trong Java

ConstructorMethod
Được sử dụng để khởi tạo trạng thái của đối tượng.Được sử dụng để thể hiện hành động của đối tượng.
Không có kiểu trả về.Có kiểu trả về.
Constructor được gọi ngầm.Phương thức được gọi tường minh.
JIT tạo ra constructor mặc định nếu bạn không có constructor nào.Phương thức không được tạo ra bởi JIT.
Tên của constructor phải giống tên lớp.Tên phương thức có thể giống hoặc khác tên lớp.

Sự khác biệt giữa từ khóa break và continue

Từ khóa break dùng để thoát ra khỏi vòng lặp ngay lập tức và chuyển sang câu lệnh tiếp theo, ở ngoài vòng lặp vừa kết thúc.

Từ khóa continue được dùng để chỉ việc vòng lặp kế tiếp sẽ được thực hiện.

Liên kết