Hiểu sâu cơ chế tăng/giảm giá trị trong Java: a++ so với ++a

Cả a++++a đều là toán tử tăng giá trị biến nguyên trong Java, nhưng chúng khác nhau về thứ tự thực thi và giá trị trả về. Sự khác biệt này không chỉ nằm ở mức mã nguồn mà còn được phản ánh rõ ràng trong bytecode do JVM sinh ra.

Dưới đây là một ví dụ minh họa:

public class IncrementAnalysis {
    public static void main(String[] args) {
        demonstrate();
    }

    static void demonstrate() {
        int value = 5;
        System.out.println(value++); // In ra 5 → sau đó value trở thành 6
        System.out.println(++value); // Trước tiên value tăng lên 7, rồi in ra 7
    }
}

Khi biên dịch, phương thức demonstrate() được chuyển thành bytecode như sau:

  public static void demonstrate();
    Code:
       0: bipush        5          // Đẩy hằng số 5 vào ngăn xếp
       2: istore_0                 // Lưu vào biến cục bộ index 0 (value)
       3: getstatic     #15       // Lấy System.out
       6: iload_0                  // Đọc giá trị hiện tại của value (5) vào ngăn xếp
       7: iinc          0, 1       // Tăng value lên 1 (giờ value = 6)
      10: invokevirtual #21       // Gọi println(int) với giá trị 5 từ ngăn xếp
      13: getstatic     #15       // Lại lấy System.out
      16: iinc          0, 1       // Tăng value lần nữa (giờ value = 7)
      19: iload_0                  // Đọc giá trị mới (7) vào ngăn xếp
      20: invokevirtual #21       // Gọi println(int) với giá trị 7
      23: return

Quá trình thực thi từng bước:

  • Dòng 0–2: Hằng số 5 được đẩy vào ngăn xếp rồi lưu vào vị trí 0 của bảng biến cục bộ — tương ứng với value = 5.
  • Dòng 3–6: Giá trị hiện tại của value (tức 5) được nạp vào ngăn xếp trước khi tăng.
  • Dòng 7: Lệnh iinc 0, 1 cập nhật value thành 6, nhưng không ảnh hưởng đến giá trị đã nằm sẵn trong ngăn xếp — nên println vẫn in 5.
  • Dòng 16: Lệnh iinc tiếp theo nâng value lên 7 trước khi đọc lại giá trị để in.
  • Dòng 19–20: Giá trị mới 7 được nạp và in ra.

Điểm mấu chốt nằm ở việc a++ tách rời thao tác *đọc giá trị* và *cập nhật biến*, trong khi ++a đảo ngược thứ tự: cập nhật trước, rồi mới đọc giá trị đã thay đổi. Cơ chế này được đảm bảo bởi trình biên dịch Java và cách JVM quản lý ngăn xếp vận hành cùng bảng biến cục bộ.

Thẻ: Java bytecode JVM increment-operator

Đăng vào ngày 2 tháng 7 lúc 20:37