Cả a++ và ++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: returnQuá 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í0của bảng biến cục bộ — tương ứng vớivalue = 5. - Dòng 3–6: Giá trị hiện tại của
value(tức5) được nạp vào ngăn xếp trước khi tăng. - Dòng 7: Lệnh
iinc 0, 1cập nhậtvaluethành6, nhưng không ảnh hưởng đến giá trị đã nằm sẵn trong ngăn xếp — nênprintlnvẫn in5. - Dòng 16: Lệnh
iinctiếp theo nângvaluelên7trướ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ộ.