Cách đây khá lâu mình đem đoạn mã đơn giản bên dưới hỏi một số bạn làm Java, cả juniors và seniors, tất cả các bạn đều bảo rằng đoạn mã này không có vấn đề gì, biên dịch và chạy được.

byte b = 1;
b = b * 2;

Thật ra thì đoạn mã trên không thể biên dịch được.

Trước tiên thử phân tích xem vì sao các bạn trả lời như vậy. Nhìn vào đoạn mã thì thấy b được khai báo kiểu byte và gán giá trị 1, khai báo này hoàn toàn hợp lệ vì tầm trị của kiểu byte trong Java từ -128 đến 127.

Dòng mã tiếp theo gán b = b * 2, lúc này biểu thức b * 2 sẽ có giá trị là 1 * 2 = 2, thuộc tầm trị [-128, 127] nên hoàn toàn có thể gán được lại cho b. Từ đây các bạn trả lời như đinh đóng cột đoạn mã trên biên dịch và chạy được là cái chắc :D

Nhưng các bạn đã nhầm, thực ra mọi thứ không diễn ra như vậy, vấn đề nằm ở dòng mã thứ 2, b = b * 2.

Khi thực hiện phép tính b * 2, Java tự động chuyển kiểu của b từ byte thành int để thực hiện phép * với 2, (2 là integer literal nên có kiểu int) và kết quả của b * 2 có kiểu int. Tới đây thì ta đã rõ vì sao b = b * 2 không thực hiện được vì thằng mang kiểu int thì không thể nào gán cho thằng mang kiểu byte được.

Quá trình tự động chuyển kiểu dữ liệu như vậy gọi là Type Promotion. Các bạn chỉ cần nhớ nguyên tắc chung khi thực hiện các biểu thức tính toán, Java sẽ tự động chuyển các kiểu dữ liệu của các toán hạng (operand) có tầm trị thấp sang kiểu dữ liệu của toán hạng có tầm trị cao hơn và kết quả của phép tính sẽ có kiểu dữ liệu của toán hạng có tầm trị cao nhất.

Cụ thể, các kiểu byte, shortchar sẽ được chuyển thành int trước tiên, sau đó nếu toán hạng tiếp theo có kiểu long thì toàn bộ biểu thức sẽ chuyển thành long, cứ thế chuyển lên float và cuối cùng là double.

byte, short, char => int => long => float => double

Chúc anh em code Java vui vẻ <3