Có, a T...
chỉ là một cú pháp cú pháp cho a T[]
.
Tham số chính thức cuối cùng trong một danh sách là đặc biệt; nó có thể là một tham số arity thay đổi , được biểu thị bằng một elipsis theo loại.
Nếu tham số chính thức cuối cùng là tham số arity biến đổi của loại T
, nó được coi là xác định tham số chính thức của loại T[]
. Phương pháp sau đó là một phương pháp arity thay đổi . Nếu không, nó là một phương pháp arity cố định . Các yêu cầu của một phương thức arity biến có thể chứa nhiều biểu thức đối số thực tế hơn các tham số chính thức. Tất cả các biểu thức đối số thực tế không tương ứng với các tham số chính thức trước tham số arity biến sẽ được ước tính và kết quả được lưu trữ trong một mảng sẽ được chuyển đến lời gọi phương thức.
Đây là một ví dụ để minh họa:
public static String ezFormat(Object... args) {
String format = new String(new char[args.length])
.replace("\0", "[ %s ]");
return String.format(format, args);
}
public static void main(String... args) {
System.out.println(ezFormat("A", "B", "C"));
// prints "[ A ][ B ][ C ]"
}
Và vâng, main
phương pháp trên là hợp lệ, bởi vì một lần nữa, String...
chỉ là String[]
. Ngoài ra, vì các mảng là covariant, a String[]
là một Object[]
, vì vậy bạn cũng có thể gọi ezFormat(args)
một trong hai cách.
Xem thêm
Varargs gotchas # 1: chuyền null
Làm thế nào varargs được giải quyết là khá phức tạp, và đôi khi nó làm những điều có thể làm bạn ngạc nhiên.
Xem xét ví dụ này:
static void count(Object... objs) {
System.out.println(objs.length);
}
count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!
Do cách giải quyết các varargs, câu lệnh cuối cùng được gọi với objs = null
, tất nhiên sẽ gây ra NullPointerException
với objs.length
. Nếu bạn muốn đưa ra một null
đối số cho tham số varargs, bạn có thể thực hiện một trong các cách sau:
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
Câu hỏi liên quan
Sau đây là mẫu của một số câu hỏi mà mọi người đã hỏi khi xử lý varargs:
Vararg gotchas # 2: thêm đối số bổ sung
Như bạn đã tìm ra, những điều sau đây không "hoạt động":
String[] myArgs = { "A", "B", "C" };
System.out.println(ezFormat(myArgs, "Z"));
// prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"
Bởi vì cách thức hoạt động của varargs, ezFormat
thực sự có 2 đối số, lần đầu tiên là a String[]
, lần thứ hai là a String
. Nếu bạn chuyển một mảng sang varargs và bạn muốn các phần tử của nó được nhận dạng thành các đối số riêng lẻ và bạn cũng cần thêm một đối số phụ, thì bạn không có lựa chọn nào khác ngoài việc tạo một mảng khác chứa phần tử phụ.
Dưới đây là một số phương pháp trợ giúp hữu ích:
static <T> T[] append(T[] arr, T lastElement) {
final int N = arr.length;
arr = java.util.Arrays.copyOf(arr, N+1);
arr[N] = lastElement;
return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
final int N = arr.length;
arr = java.util.Arrays.copyOf(arr, N+1);
System.arraycopy(arr, 0, arr, 1, N);
arr[0] = firstElement;
return arr;
}
Bây giờ bạn có thể làm như sau:
String[] myArgs = { "A", "B", "C" };
System.out.println(ezFormat(append(myArgs, "Z")));
// prints "[ A ][ B ][ C ][ Z ]"
System.out.println(ezFormat(prepend(myArgs, "Z")));
// prints "[ Z ][ A ][ B ][ C ]"
Varargs gotchas # 3: vượt qua một loạt các nguyên thủy
Nó không "hoạt động":
int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"
Varargs chỉ hoạt động với các loại tham chiếu. Autoboxing không áp dụng cho mảng nguyên thủy. Các công việc sau đây:
Integer[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"