1. Ép kiểu ngầm định (tự động)
Trong Java (cũng như các ngôn ngữ khác), biến có kiểu nghiêm ngặt — nếu biến được khai báo là int thì chỉ có thể chứa số nguyên, còn nếu là double — thì chỉ chứa số thực dấu chấm động. Nhưng trong chương trình thực tế, thường có tình huống cần “chuyển” giá trị từ biến này sang biến khác với kiểu khác. Ví dụ:
- Nhận về từ một phương thức một int, nhưng muốn dùng nó như double để tính toán với số thập phân.
- Lưu mã ký tự dưới dạng số (int), nhưng muốn lấy chính ký tự (char).
- Có kết quả tính toán ở double, nhưng cần kết quả nguyên (int), ví dụ để in ra số quả táo nguyên.
Trong Java có hai cách chuyển đổi kiểu chính: ngầm định (tự động) và tường minh (thủ công).
Đó là gì?
Ép kiểu ngầm định là khi Java tự động, “không cần bạn can thiệp”, chuyển giá trị từ kiểu này sang kiểu khác nếu thao tác đó an toàn và không gây mất dữ liệu.
Điều này xảy ra khi bạn gán giá trị của kiểu nhỏ hơn cho biến có kiểu lớn hơn. Ví dụ, từ int sang double, từ char sang int, từ float sang double.
Tương tự: Hãy tưởng tượng bạn có một cái cốc nước (int) và một cái xô (double). Nếu rót nước từ cốc sang xô — sẽ không tràn, tất cả đều chứa được. Java cho phép chuyển đổi tự động trong các trường hợp như vậy.
Ví dụ: int → double
int apples = 5;
double applesWeight = apples; // int tự động trở thành double
System.out.println(applesWeight); // 5.0
Ví dụ: char → int
Mỗi ký tự trong Java thực chất là một số trong bảng Unicode. Vì vậy chuyển đổi char sang int diễn ra tự động:
char letter = 'A';
int code = letter; // 'A' chuyển thành 65 (mã ký tự trong Unicode)
System.out.println(code); // 65
Bảng chuyển đổi ngầm định
| Từ | Có thể ngầm định sang |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Quan trọng: Ép kiểu ngầm định chỉ hoạt động theo hướng “mở rộng” (từ nhỏ sang lớn).
2. Ép kiểu tường minh (type casting)
Ép kiểu tường minh cần thiết khi bạn muốn chuyển giá trị từ kiểu lớn sang kiểu nhỏ hơn hoặc giữa các kiểu không tương thích. Lúc này Java yêu cầu bạn phải chỉ rõ rằng bạn ý thức được khả năng mất dữ liệu.
Tương tự: Bạn cố rót nước từ xô (double) vào cốc (int) — một phần nước có thể bị tràn, và Java yêu cầu bạn phải nói: “Vâng, tôi hiểu rằng một phần dữ liệu có thể bị mất!”
Cú pháp
tip_naznacheniya peremennaya = (tip_naznacheniya) vyrazhenie;
Ví dụ: double → int
double price = 12.99;
int roundedPrice = (int) price; // phần thập phân sẽ bị bỏ đi!
System.out.println(roundedPrice); // 12
Lưu ý: Không có làm tròn! Chỉ đơn giản là “cắt” mọi thứ sau dấu chấm. Để làm tròn hãy dùng Math.round().
Ví dụ: int → char
int code = 66;
char letter = (char) code; // 66 — là ký tự 'B'
System.out.println(letter); // B
Ví dụ: double → float
double d = 3.1415926535;
float f = (float) d; // mất một phần độ chính xác
System.out.println(f); // 3.1415927 (ít chữ số thập phân hơn)
3. Chuyển đổi giữa số và ký tự (char và số)
Tại sao điều này có thể?
Trong Java, ký tự (char) thực chất chỉ là các số trong bảng Unicode. Vì vậy chúng có thể chuyển đổi tự do sang int và ngược lại.
Ví dụ: char → int
char ch = '\u0416';
int code = ch;
System.out.println(code); // 1046
Ví dụ: int → char
int code = 8364;
char symbol = (char) code;
System.out.println(symbol); // €
Thực hành: in bảng chữ cái
for (int i = 65; i < 65 + 26; i++) {
System.out.print((char) i + " ");
}
// Sẽ in: A B C D ... Z
4. Chuyển đổi giữa số nguyên và số thực
int → double (ngầm định)
int count = 10;
double avg = count; // mở rộng ngầm định
System.out.println(avg); // 10.0
double → int (tường minh)
double score = 8.75;
int rounded = (int) score;
System.out.println(rounded); // 8
Làm tròn đúng theo toán học như thế nào?
Nếu cần không chỉ “bỏ” phần thập phân mà phải làm tròn về số nguyên gần nhất, hãy dùng Math.round():
double price = 8.75;
int rounded = (int) Math.round(price);
System.out.println(rounded); // 9
5. Điều gì xảy ra khi “thu hẹp” kiểu? Mất dữ liệu
Ví dụ: int → byte
int big = 300;
byte small = (byte) big;
System.out.println(small); // 44 (!)
Tại sao là 44? Bởi vì byte lưu được các giá trị từ -128 đến 127, và nếu số không “lọt” vào khoảng này — sẽ xảy ra “cắt cụt” theo modulo 256 (phần dư của phép chia).
Ví dụ: double → int
double d = 1e20;
int i = (int) d;
System.out.println(i); // -2147483648 (giá trị nhỏ nhất của int)
Số quá lớn không nằm trong khoảng của int, dẫn đến kết quả “kỳ lạ”.
6. Chuyển đổi trong khi tính toán: kiểu “hỗn hợp”
Ví dụ: int + double
int a = 3;
double b = 2.5;
double result = a + b; // int tự động trở thành double
System.out.println(result); // 5.5
Ví dụ: char + int
char ch = 'A'; // 65
int offset = 2;
char next = (char) (ch + offset); // char tự động trở thành int
System.out.println(next); // C
7. Chuyển đổi giữa số và chuỗi
Dù không hẳn là “ép kiểu”, nhưng thường gặp bài toán chuyển số thành chuỗi và ngược lại.
int → String
int x = 123;
String s = Integer.toString(x);
// hoặc đơn giản: String s = "" + x;
String → int
String s = "456";
int x = Integer.parseInt(s);
8. Lỗi thường gặp và lưu ý
Lỗi #1: Mất phần thập phân khi double → int. Rất thường người mới nghĩ rằng (int) 3.99 sẽ cho 4. Thực tế kết quả là 3, phần thập phân bị bỏ đi. Để làm tròn đúng, hãy dùng Math.round().
Lỗi #2: Thu hẹp ngầm định không hoạt động. Không thể đơn giản viết int x = 300; byte b = x; — trình biên dịch sẽ báo lỗi. Cần chỉ rõ (byte) x, nhưng hãy sẵn sàng với kết quả kỳ lạ nếu số vượt quá khoảng của byte.
Lỗi #3: Chuyển đổi giữa các kiểu không tương thích. Không thể viết (int) "123" — chuỗi phải được chuyển thành số qua Integer.parseInt().
Lỗi #4: Vấn đề với char và int. Chuyển int sang char chỉ hoạt động với các giá trị thực sự tồn tại trong Unicode. Nếu đưa vào số quá lớn, kết quả sẽ là một ký tự không như mong đợi.
Lỗi #5: Kiểu hỗn hợp trong biểu thức. Nếu biểu thức chứa int và double, kết quả luôn là double. Điều này có thể ảnh hưởng bất ngờ đến logic chương trình nếu bạn kỳ vọng số nguyên.
Lỗi #6: Làm tròn không phải là ép kiểu! (int) x không phải là làm tròn, mà chỉ là bỏ phần thập phân. Để làm tròn, hãy dùng Math.round().
GO TO FULL VERSION