1. Giới thiệu
Hãy tưởng tượng mảng một chiều như một chiếc hộp pizza dài, nơi mọi miếng được đặt thành một hàng — ngon nhưng đơn điệu.
Còn bây giờ hãy hình dung thời khóa biểu công việc hoặc bàn cờ vua. Ở đó mọi thứ được tổ chức thành hàng và cột — tức là thành bảng. Đây chính là bài toán kinh điển cho mảng hai chiều.
Trong đời sống thực, mảng hai chiều xuất hiện ở khắp nơi:
- Bảng lương nhân viên (hàng — nhân viên, cột — các tháng).
- Hình ảnh trên màn hình (mỗi “ô” — là màu của một pixel, có hai tọa độ: X và Y).
- Tính toán ma trận và xử lý dữ liệu.
- Bàn cờ vua hoặc sân chơi cờ ca-rô.
Đôi khi mảng hai chiều còn được gọi là ma trận (thuật ngữ này đến từ toán học).
Có vô số tình huống bạn, với tư cách lập trình viên, sẽ cần mảng hai chiều. Việc hiện thực hầu như mọi trò chơi trên bàn đều tương ứng sẵn với một mảng hai chiều: “Cờ vua”, “Cờ đam”, “Cờ ca-rô”, “Hải chiến (Battleship)”:

Bàn chơi của “Cờ vua” hay “Hải chiến” rất phù hợp với mảng hai chiều, nơi tọa độ của các ô chỉ là những con số. Không phải “tốt e2 ⟶ e4”, mà là “tốt (4,1) ⟶ (4,3)”. Là lập trình viên, cách này còn dễ hơn cho bạn.
2. Cú pháp khai báo mảng hai chiều
Chỉ thấy đáng sợ cho lần khai báo đầu tiên! Cùng gỡ từng bước.
Quy tắc chung
tip[][] imyaMassiva;
Ở đây hai cặp ngoặc vuông [] trống không phải lỗi của trình biên dịch sau một đêm với cà phê, mà là chỉ dẫn: mảng hai chiều.
Ví dụ
int[][] matrix;
double[][] gradesTable;
string[][] chessBoard;
Tạo mảng
Xác định kích thước: số hàng và số cột.
matrix = new int[3][4]; // 3 hàng, 4 cột
Đây là một bảng 3x4: hãy tưởng tượng một bảng Excel với 3 hàng và 4 cột.
Bạn có thể vừa khai báo biến vừa tạo mảng hai chiều ngay:
int[][] matrix = new int[3][4];
Bạn cũng có thể khởi tạo ngay bằng giá trị (tương tự mảng một chiều):
int[][] example = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Bảng 3 hàng, 3 cột
Sơ đồ trực quan
┌─────┬─────┬─────┬─────┐
│ 0 │ 1 │ 2 │ 3 │ ← cột (Columns)
├─────┼─────┼─────┼─────┤
│ 0,0 │ 0,1 │ 0,2 │ 0,3 │ ← hàng 0 (Row 0)
├─────┼─────┼─────┼─────┤
│ 1,0 │ 1,1 │ 1,2 │ 1,3 │ ← hàng 1 (Row 1)
├─────┼─────┼─────┼─────┤
│ 2,0 │ 2,1 │ 2,2 │ 2,3 │ ← hàng 2 (Row 2)
└─────┴─────┴─────┴─────┘
Mỗi phần tử được xác định bởi một cặp chỉ số [hàng, cột].
3. Đánh chỉ số và truy cập phần tử
Trong mảng hai chiều, để truy cập tới một phần tử, bạn chỉ định hai chỉ số:
- Thứ nhất — số hàng.
- Thứ hai — số cột.
// Ở hàng thứ hai (chỉ số 1), cột thứ ba (chỉ số 2)
matrix[1][2] = 99;
Nếu bạn quen đánh cờ, hãy nhớ: việc đánh chỉ số bắt đầu từ 0. Nghĩa là phần tử đầu tiên là [0][0].
Ghi và đọc
int[][] data = new int[5][2];
data[1][1] = 5; // ghi
int value = data[1][1]; // đọc
Hình dung trong bộ nhớ sẽ như sau:

4. Điền dữ liệu vào mảng hai chiều
Hãy viết đoạn mã điền ma trận bằng các số liên tiếp từ 1 đến 12, để thấy nó hoạt động như thế nào.
int[][] matrix = new int[3][4];
int value = 1;
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 4; col++)
{
matrix[row][col] = value;
value++;
}
}
Minh họa:
Sau khi thực thi:
┌────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │
├────┼────┼────┼────┤
│ 5 │ 6 │ 7 │ 8 │
├────┼────┼────┼────┤
│ 9 │ 10 │ 11 │ 12 │
└────┴────┴────┴────┘
5. Cấu trúc của mảng hai chiều
Giờ bạn sẽ biết mảng hai chiều thực sự được tổ chức như thế nào. Sẵn sàng chứ?
Mảng hai chiều — thực chất là mảng của các mảng!
Nói cách khác, nếu với mảng một chiều “biến-mảng lưu tham chiếu tới một container chứa các phần tử của mảng”, thì với mảng hai chiều, tình hình thú vị hơn một chút: biến-mảng-hai-chiều lưu tham chiếu tới một container, mà container đó lại lưu các tham chiếu tới những mảng một chiều. Tốt nhất là xem hình minh họa còn hơn cố giải thích trăm lần:

Bên trái là “biến-mảng-hai-chiều”, nó giữ tham chiếu tới “đối tượng mảng hai chiều”. Ở giữa là “đối tượng mảng hai chiều”, trong các ô của nó là tham chiếu tới các mảng một chiều — tức các hàng của mảng hai chiều. Và bên phải bạn thấy bốn mảng một chiều — các hàng của mảng hai chiều của chúng ta.
Đó là cách mảng hai chiều thật sự hoạt động. Và cách tiếp cận này mang lại cho lập trình viên Java vài lợi thế:
Thứ nhất, vì “container của các container” lưu các tham chiếu tới “các mảng-hàng”, chúng ta có thể hoán đổi các hàng rất nhanh và đơn giản. Để truy cập “container của các container”, bạn chỉ cần chỉ định một chỉ số thay vì hai. Ví dụ:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
Với đoạn mã như sau, bạn có thể hoán đổi các hàng:
// Ma trận quan trọng với dữ liệu
int[][] matrix = {
{1, 2, 3, 4, 5},
{5, 4, 3, 2, 1}
};
int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
Nếu bạn truy cập tới một ô của mảng hai chiều nhưng sau tên mảng chỉ cung cấp một chỉ số, thì bạn đang truy cập vào “container của các container”, nơi mỗi ô chứa tham chiếu tới các mảng một chiều thông thường.
6. In mảng hai chiều ra màn hình
Để in một bảng hai chiều, ta thường dùng vòng lặp lồng nhau — cũng giống như vẽ một mê cung trong console vậy. Ví dụ:
for (int row = 0; row < matrix.length; row++)
{
for (int col = 0; col < matrix[row].length; col++)
{
System.out.print(matrix[row][col] + "\t");
}
System.out.println(); // xuống dòng mới
}
Ví dụ kết quả:
1 2 3 4
5 6 7 8
9 10 11 12
Nhân tiện, đến đây bạn đã biết cách “vẽ” bảng rất đẹp chỉ bằng vài dòng mã!
GO TO FULL VERSION