Bỏ qua để đến nội dung

Ép kiểu (Type Casting)

1. Ép kiểu ngầm định (implicit / widening)

Phần tiêu đề “1. Ép kiểu ngầm định (implicit / widening)”

Khi chuyển từ kiểu nhỏ hơn sang kiểu lớn hơn (đủ chỗ chứa giá trị), Java tự động chuyển đổi mà không cần cú pháp đặc biệt - gọi là widening conversion:

int number = 100;
double value = number; // int -> double, tự động, không mất dữ liệu
System.out.println(value); // 100.0

Thứ tự widening cho kiểu số: byte -> short -> int -> long -> float -> double.

2. Ép kiểu tường minh (explicit / narrowing)

Phần tiêu đề “2. Ép kiểu tường minh (explicit / narrowing)”

Khi chuyển từ kiểu lớn hơn sang kiểu nhỏ hơn, Java không tự động chuyển - phải ép kiểu tường minh bằng cú pháp (kiểu), và có thể mất dữ liệu:

double price = 99.99;
int roundedDown = (int) price; // ép kiểu tường minh - BẮT BUỘC
System.out.println(roundedDown); // 99 - phần thập phân bị CẮT BỎ (không làm tròn)
int bigNumber = 130;
byte smallNumber = (byte) bigNumber; // byte chỉ chứa -128..127
System.out.println(smallNumber); // -126 - tràn số, kết quả không như mong đợi!

⚠️ Ép kiểu narrowing có thể làm mất thông tin (cắt phần thập phân) hoặc gây tràn số (overflow) nếu giá trị vượt quá phạm vi kiểu đích. Trình biên dịch không cảnh báo gì thêm sau khi đã ép kiểu tường minh - bạn tự chịu trách nhiệm.

int a = 10;
int b = 3;
System.out.println(a / b); // 3 - chia nguyên, mất phần thập phân
System.out.println((double) a / b); // 3.3333333333333335 - ép a sang double TRƯỚC khi chia

Ép kiểu một trong hai toán hạng sang double trước phép chia là cách phổ biến để có kết quả chia thực (xem thêm ở trang “Toán tử chia số nguyên” trong mục What the Java!).

String và kiểu số không tự động chuyển đổi qua lại - phải dùng các phương thức có sẵn:

// Số -> String
int age = 25;
String ageText = String.valueOf(age); // "25"
String ageText2 = "" + age; // "25" - nối chuỗi cũng ra kết quả tương tự
// String -> số
String input = "42";
int number = Integer.parseInt(input); // 42
double d = Double.parseDouble("3.14"); // 3.14
String invalid = "abc";
int x = Integer.parseInt(invalid); // NumberFormatException lúc chạy chương trình!

⚠️ Integer.parseInt ném ra NumberFormatException nếu chuỗi không phải là số hợp lệ - cần bọc trong try/catch khi dữ liệu đến từ người dùng (xem trang “Xử lý ngoại lệ”).

Với kiểu tham chiếu (object), ép kiểu chỉ hợp lệ trong một cây phân cấp kế thừa, và có thể ném ClassCastException nếu đối tượng thực tế không thuộc kiểu đích:

Object obj = "Hello";
String s = (String) obj; // OK - obj thực sự là một String
Object obj2 = Integer.valueOf(5);
String s2 = (String) obj2; // ClassCastException lúc chạy chương trình!

Chi tiết về ép kiểu đối tượng sẽ được nói kỹ hơn ở phần Hướng đối tượng (kế thừa, đa hình).

  • Widening (nhỏ → lớn): tự động, an toàn, không mất dữ liệu
  • Narrowing (lớn → nhỏ): phải ép kiểu tường minh (kiểu), có thể mất dữ liệu hoặc tràn số
  • String và số không tự chuyển đổi qua lại - dùng Integer.parseInt/Double.parseDoubleString.valueOf
  • Ép kiểu đối tượng sai kiểu thực tế sẽ ném ClassCastException lúc chạy chương trình