Trong bài này, tôi sẽ giới thiệu các bạn mảng trong Java, cách khai báo các biến mảng, tạo các mảng, xử lý các mảng bởi sử dụng chỉ mục của các biến, mảng một chiều và mảng đa chiều trong Java.
Mảng là gì?
Mảng (array) trong Java là một tập hợp các phần tử có cùng kiểu dữ liệu, có địa chỉ tiếp nhau trên bộ nhớ (memory). Mảng có số phần tử cố định và bạn không thể thay đổi kích thước của nó.
Kiểu dữ liệu trong mảng có thể là kiểu nguyên thủy (primitive type) hoặc kiểu đối tượng (object).
Mảng trong Java là dựa trên chỉ mục (index), phần tử đầu tiên của mảng được lưu trữ tại chỉ mục 0.
Ví dụ: mảng một chiều có 5 phần tử, chứa các số int
Ngoài các mảng 1 chiều, đôi khi bạn cũng phải làm việc với mảng 2 chiều hoặc nhiều chiều. Một mảng 2 chiều, các phần tử của nó sẽ được đánh hai chỉ số, chỉ số hàng và chỉ số cột. Dưới đây là hình ảnh một mảng 2 chiều.
Ví dụ: mảng hai chiều, mỗi chiều có 5 phần tử, chứa các số int
Mảng một chiều
Khai báo biến mảng trong Java
Khai báo một mảng, chưa chỉ rõ số phần tử:
Cú pháp:
Kieu_du_lieu[] ten_bien;
Kieu_du_lieu có thể là kiểu nguyên thủy (primitive) hoặc kiểu đối tượng (object).
Ví dụ: int[] arr;
Khởi tạo số lượng phần tử của mảng
ten_bien = new Kieu_du_lieu[kich_thuoc_mang];
Ví dụ: khởi tạo mảng có 5 phần tử, chưa được gán giá trị cụ thể
arr = new int[5];
Khai báo một mảng, và chỉ rõ số phần tử, các phần tử chưa được gán giá trị cụ thể:
Kieu_du_lieu[] ten_bien = new Kieu_du_lieu[kich_thuoc_mang];
Ví dụ: int[] arr = new int[5];
Khai báo một mảng với các phần tử được gán giá trị cụ thể:
Kieu_du_lieu[] ten_bien = { giatri0, giatri1, ..., giatriN };
Ví dụ:
int[] arr = { 11, 12, 13, 14, 15 };
Ví dụ sử dụng mảng
package com.gpcoder; public class ArraySample1 { public static void main(String[] args) { // Khai báo một mảng 5 phần tử int[] arr = new int[5]; // Chú ý: phần tử đầu tiên của mảng có chỉ số là 0: // Gán giá trị cho phần tử đầu tiên (Chỉ số 0) arr[0] = 11; // Gán giá trị cho phần tử thứ hai (Chỉ số 1) arr[1] = 12; arr[2] = 13; arr[3] = 14; arr[4] = 15; // In ra màn hình Console số phần tử của mảng. System.out.println("Số lượng phần tử = " + arr.length); // Kiểm tra nếu số lượng phần từ của mảng >= 2 thì hiển thị giá trị của phần tử thứ 2 if (arr.length >= 2) { // In ra phần tử tại chỉ số 1 (Phần tử thứ 2 trong mảng) System.out.println(" arr[1]=" + arr[1]); } // Sử dụng vòng lặp for để in ra các phần tử trong mảng. System.out.println("Sử dụng for"); for (int index = 0; index < arr.length; index++) { System.out.println("Element " + index + " = " + arr[index]); } // Sử dụng vòng lặp foreach để in ra các phần tử trong mảng. System.out.println("Sử dụng foreach"); int index = 0; for (int value : arr) { System.out.println("Element " + index + " = " + value); index++; } } }
Kết quả:
Số lượng phần từ = 5 arr[1]=12 Sử dụng for Element 0 = 11 Element 1 = 12 Element 2 = 13 Element 3 = 14 Element 4 = 15 Sử dụng foreach Element 0 = 11 Element 1 = 12 Element 2 = 13 Element 3 = 14 Element 4 = 15
Lưu ý: nên kiểm tra length trước khi sử dụng để tránh lỗi truy cập ngoài chỉ số mảng ArrayIndexOfBoundException
Như ví dụ trên, nếu ta truy cập phần tử arr[5] sẽ bị lỗi ArrayIndexOfBoundException
Ví dụ sử dụng vòng lặp for để khởi tạo giá trị
package com.gpcoder; public class ArraySample2 { public static void main(String[] args) { // Khai báo một mảng 5 phần tử int[] arr = new int[5]; // Sử dụng for để khởi tạo giá trị trong mảng for (int i = 0; i < 5; i++) { arr[i] = 11 + i; } // Duyệt qua các phần từ trong mảng sử dụng while int index = 0; int numberOfElement = arr.length; while (index < numberOfElement) { System.out.print(arr[index] + " "); index++; } } }
Kết quả:
11 12 13 14 15
Sao chép một mảng trong Java
Bạn có thể sao chép một mảng này sang mảng khác bởi phương thức arraycopy của lớp System.
Cú pháp:
package com.gpcoder; public class ArrayCopySample { public static void main(String[] args) { char[] copyFrom = { 'w', 'e', 'c', 'o', 'm', 'e', 't', 'o', 'g', 'p', 'c', 'o', 'd', 'e', 'r' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 8, copyTo, 0, 7); System.out.println(new String(copyTo)); } }
Ví dụ:
package com.gpcoder; public class ArrayCopySample { public static void main(String[] args) { char[] copyFrom = { 'w', 'e', 'c', 'o', 'm', 'e', 't', 'o', 'g', 'p', 'c', 'o', 'd', 'e', 'r' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 8, copyTo, 0, 7); System.out.println(new String(copyTo)); } }
Kết quả:
gpcoder
Các phương thức tiện ích cho mảng 1 chiều (Arrays)
Java cung cấp cho bạn một số phương thức tĩnh tiện ích dành cho mảng, chẳng hạn: sắp xếp mảng, gán các giá trị cho toàn bộ các phần tử của mảng, tìm kiếm, so sánh mảng… Các phương thức này được định nghĩa trong lớp Arrays.
// Chuyển một mảng có kiểu T sang danh sách (List) có kiểu T // T là kiểu đối tượng (Object) public static <T> List<T> asList(T... a) // Tìm kiếm chỉ số của một giá trị xuất hiện trong mảng. // (Sử dụng thuật toán tìm kiếm nhị phân (binary search)) public static int binarySearch(type[] a, type key) // Sắp xếp các giá trị của mảng tăng dần public static void sort(type[] a) // Copy các phần tử của một mảng để tạo ra một mảng mới với độ dài chỉ định. public static int[] copyOf(type[] original, type newLength) // Copy một phạm vi chỉ định các phần tử của mảng để tạo một mảng mới public static double[] copyOfRange(type[] original, int from, int to) // So sánh hai mảng public static boolean equals(type[] a, long[] a2) // Gán cùng một giá trị cho tất cả các phần tử của mảng. public static void fill(type[] a, type val) // Chuyển một mảng thành chuỗi (string) public static String toString(type[] a)
Ví dụ:
package com.gpcoder; import java.util.Arrays; import java.util.List; public class ArraySample3 { public static void main(String[] args) { // Khai báo một mảng 5 phần tử kiểu nguyên thủy (primitive) int[] arr = { 15, 5, 10, 30, 25 }; System.out.println("Gọi hàm toString để hiển thị mảng: "); // Chuyển một mảng thành chuỗi (string) System.out.println(Arrays.toString(arr)); // Sắp xếp các giá trị của mảng tăng dần Arrays.sort(arr); System.out.println("Sau khi gọi hàm sort: "); // Chuyển một mảng thành chuỗi (string) System.out.println(Arrays.toString(arr)); // Tìm kiếm chỉ số của một giá trị xuất hiện trong mảng. // Mảng phải được sắp xếp trước khi gọi hàm binarySearch int index = Arrays.binarySearch(arr, 30); if (index < 0) { System.out.println("Không tìm thấy giá trị"); } else { System.out.println("Tìm thấy giá trị 30 tại index " + index); } // Gán cùng một giá trị cho tất cả các phần tử của mảng. Arrays.fill(arr, 11); System.out.println("Sau khi gọi hàm fill: "); // Chuyển một mảng thành chuỗi (string) System.out.println(Arrays.toString(arr)); // Khai báo một mảng 5 phần tử kiểu đối tượng (object) Integer[] arr2 = { 15, 5, 10, 30, 25 }; // Chuyển một mảng có kiểu T sang danh sách (List) có kiểu T // List: chỉ sử dụng được với object, không sử dụng kiểu nguyên thủy (primitive) List<Integer> list = Arrays.asList(arr2); System.out.println("Sau khi gọi hàm asList: "); // Chuyển một mảng thành chuỗi (string) System.out.println(list); } }
Kết quả:
Gọi hàm toString để hiển thị mảng: [15, 5, 10, 30, 25] Sau khi gọi hàm sort: [5, 10, 15, 25, 30] Tìm thấy giá trị 30 tại index 4 Sau khi gọi hàm fill: [11, 11, 11, 11, 11] Sau khi gọi hàm asList: [15, 5, 10, 30, 25]
Mảng hai chiều
Khai báo mảng 2 chiều
Có 3 cách để khai báo một mảng 2 chiều:
// Khai báo một mảng có 5 dòng, 10 cột Kieu_du_lieu[][] ten_bien_1 = new Kieu_du_lieu[5][10]; // Khai báo một mảng 2 chiều có 5 dòng. // (Mảng của mảng) Kieu_du_lieu[][] ten_bien_2 = new Kieu_du_lieu[5][]; // Khai báo một mảng 2 chiều, chỉ định giá trị các phần tử. Kieu_du_lieu[][] ten_bien_3 = new Kieu_du_lieu[][] { { value00, value01, value02 }, { value10, value11, value12 } };
- Giá trị mặc định 0 ứng với các kiểu byte, double, float, long, int, short.
- Giá trị mặc định false ứng với kiểu boolean.
- Giá trị mặc định ‘\u0000’ (Ký tự null) ứng với kiểu char.
Ngược lại, nếu bạn khai báo một mảng của kiểu tham chiếu, nếu một phần tử của mảng không được chỉ định giá trị, nó sẽ có giá trị mặc định là null.
Ví dụ sử dụng mảng hai chiều
package com.gpcoder; public class TwoDimensionalSample1 { public static void main(String[] args) { // Khai báo một mảng 2 chiều với 2 dòng, 3 cột // Các phần tử có giá trị mặc định int[][] arr = new int[2][3]; // Số dòng của mảng 2 chiều. System.out.println("Số dòng của mảng 2 chiều: "+ arr.length); // = 2 System.out.println("Hiển thị mảng rỗng"); for (int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { System.out.println("arr[" + row + "," + col + "]=" + arr[row][col]); } } System.out.println(); System.out.println("Khỏi tạo giá trị mảng"); // Gán các giá trị cho các phần tử for (int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { arr[row][col] = row + col; } } System.out.println(); System.out.println("Hiển thị giá trị sau khi khởi tạo"); for (int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { System.out.println("arr[" + row + "," + col + "]=" + arr[row][col]); } } } }
Kết quả:
Số dòng của mảng 2 chiều: 2 Hiển thị mảng rỗng arr[0,0]=0 arr[0,1]=0 arr[0,2]=0 arr[1,0]=0 arr[1,1]=0 arr[1,2]=0 Khỏi tạo giá trị mảng Hiển thị giá trị sau khi khởi tạo arr[0,0]=0 arr[0,1]=1 arr[0,2]=2 arr[1,0]=1 arr[1,1]=2 arr[1,2]=3
Trong Java mảng 2 chiều thực sự là một mảng của mảng, vì vậy bạn có thể khai báo một mảng 2 chiều chỉ cần chỉ định số dòng, không cần phải chỉ rõ số cột. Chính vì mảng 2 chiều là “Mảng của mảng” nên thuộc tính length của mảng 2 chiều trả về số dòng của mảng.
Ví dụ:
package com.gpcoder; public class TwoDimensionalSample1 { public static void main(String[] args) { // Khai báo một mảng 2 chiều (Mảng của mảng) // Khởi tạo mảng có 2 dòng int[][] arr = new int[2][]; // Khởi tạo giá trị cho phần từ thứ 2 arr[0] = new int[] { 1, 2 }; // Khởi tạo giá trị cho phần tử thứ nhất arr[1] = new int[] { 1, 2, 3, 4 }; for (int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { System.out.println("Giá trị tại [" + row + "][" + col + "]=" + arr[row][col]); } } } }
Kết quả
Giá trị tại [0][0]=1 Giá trị tại [0][1]=2 Giá trị tại [1][0]=1 Giá trị tại [1][1]=2 Giá trị tại [1][2]=3 Giá trị tại [1][3]=4
Lợi thế và hạn chế của mảng trong Java
Lợi thế
- Cho phép xử lí nhiều thành phần dữ liệu trong cùng 1 thời điểm.
- Bộ nhớ chỉ được cấp cho mảng khi mảng thực sự được sử dụng.
- Truy cập ngẫu nhiên: chúng ta có thể lấy bất cứ dữ liệu nào ở tại bất cứ vị trí chỉ mục nào.
Hạn chế
- Giới hạn kích cỡ: Kích thước mảng cố định không thay đổi. Nó không tăng kích thước của nó tại runtime. Để xử lý vấn đề này, Collection Framework được sử dụng trong Java.
- Các phần tử của một mảng là được đặt và tham chiếu liên tiếp nhau trong bộ nhớ, điều đó là khó khăn khi ta cố tình bỏ đi một phần tử nào đó trong mảng, nó mất tính liên tiếp. Thông thường một kỹ thuật mà thường sử dụng là tạo một mảng mới lưu trữ các đối tượng của mảng ban đầu và bỏ đi các phần tử không cần thiết, tuy nhiên điều này làm giảm hiệu năng của chương trình.
- Với trường hợp mở rộng mảng cũng với kỹ thuật tương tự là khởi tạo một mảng mới với kích cỡ lớn hơn sau đó thì copy các phần tử mảng cũ cho mảng mới .
- Chỉ lưu trữ được duy nhất cùng một kiểu dữ liệu trong mảng
Tài liệu tham khảo:
- https://www.tutorialspoint.com/java/java_arrays.htm
- http://o7planning.org/vi/11567/mang-array-trong-java