Java bỏ chọn: tạo mảng chung không được kiểm tra cho tham số varargs


111

Tôi đã đặt Netbeans để hiển thị cảnh báo chưa được kiểm tra trong mã Java của mình, nhưng tôi không hiểu lỗi trên các dòng sau:

private List<String> cocNumbers;
private List<String> vatNumbers;
private List<String> ibans;
private List<String> banks;
...
List<List<String>> combinations = Utils.createCombinations(cocNumbers, vatNumbers, ibans);

Cung cấp:

[unchecked] unchecked generic array creation for varargs parameter of type List<String>[]

Nguồn phương pháp:

/**
 * Returns a list of all possible combinations of the entered array of lists.
 *
 * Example: [["A", "B"], ["0", "1", "2"]]
 * Returns: [["A", "0"], ["A", "1"], ["A", "2"], ["B", "0"], ["B", "1"], ["B", "2"]]
 *
 * @param <T> The type parameter
 * @param elements An array of lists
 * @return All possible combinations of the entered lists
 */
public static <T> List<List<T>> createCombinations(List<T>... elements) {
    List<List<T>> returnLists = new ArrayList<>();

    int[] indices = new int[elements.length];
    for (int i = 0; i < indices.length; i++) {
        indices[i] = 0;
    }

    returnLists.add(generateCombination(indices, elements));
    while (returnLists.size() < countCombinations(elements)) {
        gotoNextIndex(indices, elements);
        returnLists.add(generateCombination(indices, elements));
    }

    return returnLists;
}

Chính xác thì điều gì đang xảy ra và tôi sẽ sửa nó như thế nào, vì tôi cho rằng để lại các cảnh báo không được kiểm tra trong mã không phải là một ý kiến ​​hay?

Quên đề cập, nhưng tôi đang sử dụng Java 7.

Chỉnh sửa : Ngoài ra, bây giờ tôi thấy rằng phương pháp có như sau:

[unchecked] Possible heap pollution from parameterized vararg type List<T>
  where T is a type-variable:
    T extends Object declared in method <T>createCombinations(List<T>...)

17
Bất cứ điều gì khác mà bạn làm, trong Java bạn không cần phải khởi tạo một mảng int mới được tạo ra với 0s ...
Thomas Mueller

1
@ThomasMueller Bắt tốt ở đó
skiwi

Câu trả lời:


165

Như janoh.janoh đã đề cập ở trên, varargs trong Java chỉ là một đường cú pháp cho các mảng cộng với việc tạo ngầm một mảng tại trang web đang gọi. Vì thế

List<List<String>> combinations =
    Utils.createCombinations(cocNumbers, vatNumbers, ibans);

thực sự là

List<List<String>> combinations =
    Utils.createCombinations(new List<String>[]{cocNumbers, vatNumbers, ibans});

Nhưng như bạn có thể biết, điều new List<String>[]này không được phép trong Java, vì những lý do đã được đề cập trong nhiều câu hỏi khác, nhưng chủ yếu liên quan đến thực tế là các mảng biết loại thành phần của chúng trong thời gian chạy và kiểm tra trong thời gian chạy xem các phần tử được thêm vào có khớp với thành phần của nó không. loại, nhưng không thể kiểm tra này đối với các loại được tham số hóa.

Dù sao, thay vì thất bại, trình biên dịch vẫn tạo ra mảng. Nó làm điều gì đó tương tự như sau:

List<List<String>> combinations =
    Utils.createCombinations((List<String>[])new List<?>[]{cocNumbers, vatNumbers, ibans});

Điều này tiềm ẩn không an toàn, nhưng không hẳn là không an toàn. Hầu hết các phương thức varargs chỉ cần lặp qua các phần tử varargs và đọc chúng. Trong trường hợp này, nó không quan tâm đến kiểu thời gian chạy của mảng. Đây là trường hợp của phương pháp của bạn. Vì bạn đang sử dụng Java 7, bạn nên thêm @SafeVarargschú thích vào phương thức của mình và bạn sẽ không nhận được cảnh báo này nữa. Chú thích này nói về cơ bản, phương pháp này chỉ quan tâm đến kiểu của các phần tử, không phải kiểu của mảng.

Tuy nhiên, có một số phương thức varargs sử dụng kiểu thời gian chạy của mảng. Trong trường hợp này, nó có khả năng mất an toàn. Đó là lý do tại sao cảnh báo ở đó.


16
Cảm ơn bạn đã không chỉ đề cập đến SafeVarags mà còn cho chúng tôi biết khi nào chúng tôi có thể sử dụng nó.
KitsuneYMG

12
Nếu nó không hiển thị ngay lập tức với bất kỳ ai (như tôi không thấy), thì Javadocs cho @SafeVarargscó một ví dụ về phương pháp không an toàn docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig

3
Vì vậy, @SafeVarargscó thể được sử dụng khi phương thức của bạn chỉ sử dụng các phần tử của mảng và không (và sẽ không bao giờ) tạo ra các phần tử để đưa vào mảng? Cần phải đặc biệt cẩn thận nếu bạn gán đối số mảng cho một trường có thể được thao tác bởi các phương thức khác vì việc xác định rằng không có hoạt động không an toàn nào được thực hiện trên nó có thể không phải là chuyện nhỏ.
neXus

13

Bởi vì trình biên dịch java sử dụng tạo mảng ngầm định cho varargs và java không cho phép tạo mảng chung (bởi vì đối số kiểu không thể truy cập lại).

Đoạn mã dưới đây là đúng (các thao tác này được phép với mảng), vì vậy cần có cảnh báo bỏ chọn:

public static <T> List<List<T>> createCombinations(List<T> ... lists) {
    ((Object[]) lists)[0] = new ArrayList<Integer>();
    // place your code here
}

Xem giải thích toàn diện tại đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.