ไม่เลือก Java: ไม่ได้เลือกการสร้างอาร์เรย์ทั่วไปสำหรับพารามิเตอร์ varargs


112

ฉันได้ตั้งค่า Netbeans ให้แสดงคำเตือนที่ไม่ได้ตรวจสอบในโค้ด Java ของฉัน แต่ฉันไม่เข้าใจข้อผิดพลาดในบรรทัดต่อไปนี้:

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);

ให้:

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

แหล่งที่มาของวิธีการ:

/**
 * 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;
}

เกิดอะไรขึ้นกันแน่และฉันจะแก้ไขได้อย่างไรเนื่องจากฉันคิดว่าการทิ้งคำเตือนที่ไม่เลือกไว้ในรหัสนั้นไม่ใช่ความคิดที่ดี

ลืมพูดถึง แต่ฉันใช้ Java 7

แก้ไข : ตอนนี้ฉันเห็นว่าวิธีการดังต่อไปนี้:

[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
ไม่ว่าคุณจะทำอะไรก็ตามใน Java คุณไม่จำเป็นต้องเริ่มต้นอาร์เรย์ int ที่สร้างขึ้นใหม่ด้วย 0s ...
Thomas Mueller

1
@ThomasMueller จับดีที่นั่น
skiwi

คำตอบ:


166

ดังที่ janoh.janoh ได้กล่าวไว้ข้างต้น varargs ใน Java เป็นเพียงน้ำตาลเชิงไวยากรณ์สำหรับอาร์เรย์บวกกับการสร้างอาร์เรย์โดยนัยที่ไซต์การเรียกใช้ ดังนั้น

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

เป็นความจริง

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

แต่อย่างที่คุณทราบnew List<String>[]ไม่อนุญาตให้ใช้ใน Java ด้วยเหตุผลที่ครอบคลุมในคำถามอื่น ๆ อีกมากมาย แต่ส่วนใหญ่เกี่ยวข้องกับข้อเท็จจริงที่ว่าอาร์เรย์รู้ประเภทส่วนประกอบของมันในขณะรันไทม์และตรวจสอบที่รันไทม์ว่าองค์ประกอบที่เพิ่มตรงกับส่วนประกอบหรือไม่ type แต่การตรวจสอบนี้ไม่สามารถทำได้สำหรับประเภทที่กำหนดพารามิเตอร์

อย่างไรก็ตามแทนที่จะล้มเหลวคอมไพเลอร์ยังคงสร้างอาร์เรย์ มันทำสิ่งที่คล้ายกับสิ่งนี้:

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

สิ่งนี้อาจไม่ปลอดภัย แต่ไม่จำเป็นต้องไม่ปลอดภัย วิธีการ varargs ส่วนใหญ่เพียงแค่วนซ้ำองค์ประกอบของ varargs แล้วอ่าน ในกรณีนี้จะไม่สนใจประเภทรันไทม์ของอาร์เรย์ นี่เป็นกรณีของวิธีการของคุณ เนื่องจากคุณใช้ Java 7 คุณควรเพิ่ม@SafeVarargsคำอธิบายประกอบลงในวิธีการของคุณและคุณจะไม่ได้รับคำเตือนนี้อีกต่อไป คำอธิบายประกอบนี้กล่าวโดยทั่วไปวิธีนี้จะให้ความสำคัญกับประเภทขององค์ประกอบเท่านั้นไม่ใช่ประเภทของอาร์เรย์

อย่างไรก็ตามมีบางวิธี varargs ที่ใช้ชนิดรันไทม์ของอาร์เรย์ ในกรณีนี้อาจไม่ปลอดภัย นั่นเป็นเหตุผลที่มีคำเตือน


16
ขอบคุณที่ไม่เพียง แต่พูดถึง SafeVarags แต่ยังช่วยบอกเราว่าเราสามารถใช้งานได้เมื่อใด
KitsuneYMG

12
หากไม่ชัดเจนสำหรับทุกคนในทันที (เหมือนไม่ใช่สำหรับฉัน) Javadocs @SafeVarargsมีตัวอย่างวิธีการที่ไม่ปลอดภัยdocs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig

3
ดังนั้น@SafeVarargsอาจใช้เมื่อวิธีการของคุณใช้เฉพาะองค์ประกอบของอาร์เรย์และไม่ (และจะไม่) สร้างองค์ประกอบเพื่อใส่ลงในอาร์เรย์? ต้องใช้ความระมัดระวังเป็นพิเศษหากคุณกำหนดอาร์กิวเมนต์อาร์เรย์ให้กับฟิลด์ที่อาจถูกจัดการโดยวิธีการอื่นเนื่องจากการพิจารณาว่าไม่มีการดำเนินการที่ไม่ปลอดภัยในการดำเนินการอาจไม่สำคัญ
neXus

13

เนื่องจากคอมไพเลอร์ java ใช้การสร้างอาร์เรย์โดยนัยสำหรับ varargs และ java ไม่อนุญาตให้สร้างอาร์เรย์ทั่วไป (เนื่องจากอาร์กิวเมนต์ type ไม่สามารถ reifiable)

รหัสด้านล่างนี้ถูกต้อง (อนุญาตให้ดำเนินการกับอาร์เรย์ได้) ดังนั้นจึงจำเป็นต้องมีคำเตือนที่ไม่เลือก:

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

ดูคำอธิบายที่ครอบคลุมที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.