CodeGym /Các khóa học /JAVA 25 SELF /Các kiểu bao bọc (wrapper) trong Java

Các kiểu bao bọc (wrapper) trong Java

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Trong Java tồn tại hai họ dữ liệu khác nhau. Thứ nhất — các kiểu nguyên thủy: int, char, double, boolean và các kiểu khác. Chúng đơn giản và nhanh: giá trị được lưu trực tiếp trong ô nhớ. Họ thứ hai — các kiểu tham chiếu, tức là đối tượng: biến lưu một tham chiếu tới nơi đối tượng nằm trong bộ nhớ.

Đôi khi cần dùng một kiểu nguyên thủy như một đối tượng. Nhưng kiểu nguyên thủy vốn dĩ không phải đối tượng. Trong những trường hợp như vậy, các lớp bao bọc chuyên dụng sẽ giúp ích.

Các kiểu bao bọc là các lớp lưu giữ bên trong giá trị của kiểu nguyên thủy và cho phép làm việc với nó như với đối tượng. Ví dụ, với int — lớp Integer, với doubleDouble, với charCharacter, với booleanBoolean. Các lớp này cung cấp các phương thức: Integer.parseInt(), Double.isInfinite(), Character.isLetter(), Boolean.parseBoolean() v.v.

Ví dụ lấy đối tượng Integer từ nguyên thủy int:

// Nguyên thủy
int a = 10;

// Đối tượng bao bọc
Integer b = Integer.valueOf(10);

Trong biến a lưu chính số 10. Còn biến b lưu một tham chiếu tới đối tượng, đối tượng này chứa 10 bên trong.

2. Vì sao cần wrapper

Kiểu nguyên thủy luôn là một giá trị cụ thể, không thể gán bằng null. Đối tượng có thể không tồn tại và mang giá trị rỗng — tiện khi cần biểu thị “không rõ” hoặc “không có”.

Kiểu nguyên thủy không có phương thức. Không thể gọi trên một số thứ như x.toString(). Wrapper cung cấp các khả năng đó: Integer.parseInt("123") chuyển chuỗi thành số, và có thể chuyển số thành chuỗi bằng toString().

Tóm lại: cần wrapper ở nơi yêu cầu đối tượng — khả năng lưu null, gọi phương thức, truyền giá trị vào API chỉ chấp nhận đối tượng (ví dụ, các collection như List<Integer>).

Danh sách đầy đủ các kiểu bao bọc

Kiểu nguyên thủy Lớp bao bọc
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
boolean
Boolean

3. Đóng gói (boxing) và mở gói (unboxing)

Khi bạn tự tạo đối tượng bao bọc, bạn lấy kiểu nguyên thủy và “đóng gói” nó vào trong đối tượng:

int primitive = 42;
Integer wrapper = Integer.valueOf(primitive); // boxing

Để lấy lại giá trị nguyên thủy — “unbox” — dùng, chẳng hạn, intValue():

Integer wrapper = Integer.valueOf(42);
int primitive = wrapper.intValue(); // unboxing

Tự động boxing (Autoboxing)

Trình biên dịch sẽ tự thêm lời gọi valueOf(), nếu bạn gán một nguyên thủy cho biến kiểu bao bọc:

int a = 10;
Integer b = a; // autoboxing (Integer.valueOf(a))

Tự động unboxing (Unboxing)

Tình huống ngược lại — khi đối tượng bao bọc được dùng ở nơi cần kiểu nguyên thủy:

Integer c = 20;
int d = c; // unboxing (c.intValue())

int a = 10; // nguyên thủy
Integer b = a; // autoboxing
Integer c = Integer.valueOf(20);
int d = c; // unboxing
Autoboxing và unboxing

4. Những cạm bẫy

So sánh wrapper. Toán tử == đối với đối tượng so sánh tham chiếu, không phải giá trị:

Integer m = 200;
Integer n = 200;
System.out.println(m == n); // false, vì đây là các đối tượng khác nhau

Java cache các wrapper của số trong khoảng từ -128 đến 127, vì vậy đôi khi == sẽ trả về true, còn đôi khi — false. Để so sánh giá trị, luôn dùng equals():

Integer x = 100;
Integer y = 100;
System.out.println(x == y);      // true, trùng cache
System.out.println(x.equals(y)); // true, so sánh theo giá trị

NullPointerException khi unboxing. Nếu wrapper bằng null mà bạn cố unbox — bạn sẽ nhận ngoại lệ:

Integer value = null;
int primitive = value; // Lỗi! NullPointerException

Hiệu năng và bộ nhớ. Wrapper chậm hơn kiểu nguyên thủy và tốn nhiều bộ nhớ hơn. Ở các đoạn mã nóng và khi làm việc với mảng số lớn, hãy chọn kiểu nguyên thủy.

5. Ví dụ

Ví dụ với Integer và Double

Chuyển chuỗi thành số:

String text = "123";
int number = Integer.parseInt(text);
System.out.println(number); // 123

Kiểm tra các giá trị đặc biệt của số thực:

double d = 1.0 / 0;
System.out.println(Double.isInfinite(d)); // true

double nan = 0.0 / 0.0;
System.out.println(Double.isNaN(nan)); // true

Ví dụ với Character

char lưu một ký tự; wrapper Character cung cấp các phép kiểm tra tiện lợi:

char ch = 'A';
Character wrapper = ch; // autoboxing

System.out.println(Character.isLetter(ch)); // true
System.out.println(Character.isDigit(ch));  // false
System.out.println(Character.toLowerCase(ch)); // 'a'

Ví dụ với Boolean

Kiểu nguyên thủy boolean chỉ có true/false. Wrapper Boolean cho phép lưu cả null:

Boolean flag = null; // hợp lệ
flag = Boolean.TRUE; // hằng đặc biệt

System.out.println(flag); // true

Chuyển chuỗi thành giá trị logic:

String s1 = "true";
String s2 = "false";
boolean b1 = Boolean.parseBoolean(s1);
boolean b2 = Boolean.parseBoolean(s2);

System.out.println(b1); // true
System.out.println(b2); // false
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION