ไม่สามารถสร้างอาร์เรย์ของ LinkedLists ใน Java …?


102

ฉันกำลังทำงานกับคลาสเมทริกซ์แบบกระจัดกระจายที่ต้องการใช้อาร์เรย์LinkedListเพื่อเก็บค่าของเมทริกซ์ แต่ละองค์ประกอบของอาร์เรย์ (เช่นแต่ละรายการLinkedList) แทนแถวของเมทริกซ์ และแต่ละองค์ประกอบในLinkedListอาร์เรย์แสดงถึงคอลัมน์และค่าที่เก็บไว้

ในชั้นเรียนของฉันฉันมีการประกาศอาร์เรย์เป็น:

private LinkedList<IntegerNode>[] myMatrix;

และในตัวสร้างของฉันสำหรับSparseMatrixฉันพยายามกำหนด:

myMatrix = new LinkedList<IntegerNode>[numRows];

ข้อผิดพลาดที่ฉันได้รับคือ

ไม่สามารถสร้างอาร์เรย์ทั่วไปของLinkedList<IntegerNode>.

ดังนั้นฉันมีสองประเด็นเกี่ยวกับสิ่งนี้:

  1. ฉันทำอะไรผิดและ
  2. เหตุใดประเภทจึงเป็นที่ยอมรับในการประกาศสำหรับอาร์เรย์หากไม่สามารถสร้างได้

IntegerNodeเป็นคลาสที่ฉันสร้างขึ้น และไฟล์คลาสทั้งหมดของฉันรวมอยู่ด้วยกัน

คำตอบ:


64

คุณไม่สามารถใช้การสร้างอาร์เรย์ทั่วไปได้ มันเป็นข้อบกพร่อง / คุณสมบัติของ java generics

วิธีที่ไม่มีคำเตือน ได้แก่ :

  1. การใช้ List of Lists แทน Array of Lists:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. การประกาศคลาสพิเศษสำหรับ Array of Lists:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }

19
ทางเลือกที่ดีกว่าสำหรับวิธีแก้ปัญหาหลังคือ: class IntegerNodeList extends List<IntegerNode> {}
kamasheto

การใช้งานนี้ช้ามาก การรับองค์ประกอบ [1000] [2000] (nodeLists.get (1000) .get (2000)) จะทำให้ LinkedList วนซ้ำ 3000 ครั้ง! หลีกเลี่ยง LinkedList หากใครก็ตามอาจทำดัชนีไว้ในนั้น ArrayList จะจัดทำดัชนีได้เร็วขึ้น แต่โซลูชันของ Fredrik นั้นดีกว่าโดยรวม
Steve Zobell

142

ด้วยเหตุผลบางประการคุณต้องระบุประเภทและทำการประกาศดังนี้:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];

ฉันค้นคว้าปัญหาที่คล้ายกันและอ่านว่านักแสดงข้างต้นเป็น 'แฮ็ก' ทั่วไปที่ใช้ทั่วกรอบคอลเลกชัน
ลูกา

15
IMO นี่ควรเป็นคำตอบที่เลือก ฉันยังไม่ได้ทดลอง แต่ฉันรู้สึกว่าวิธี # 2 ของ Sergey สร้างค่าใช้จ่ายได้ไม่น้อย และฉันเป็นบวกที่ # 1 ทำ รายการไม่มีประสิทธิภาพเท่ากับอาร์เรย์ในหลาย ๆ วิธีซึ่งฉันจะไม่ลงรายละเอียดที่นี่ แต่ฉันได้ทำการทดลองและเห็นการชะลอตัวครั้งใหญ่เมื่อใช้รายการเทียบกับอาร์เรย์ เพียงแค่จัดการอาร์เรย์ของคุณเองและจัดสรรใหม่ได้เร็วกว่าการเพิ่มสิ่งต่างๆลงในรายการ
Ricket

@Ricket ฉันเห็นด้วยนำมาจากibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter

4
ฉันยังคงได้รับคำเตือน "Type safety: unchecked cast" อยู่ วิธีแก้ปัญหาของ Bob ดูสะอาดที่สุดสำหรับฉัน
มาร์โกแลคโควิช

3
ใน JDK 7 ข้างต้นให้คำเตือน Rawtypes ซึ่งสามารถแก้ไขได้โดยใช้ประเภท <?> ที่ไม่ถูกผูกไว้ แต่คุณยังคงได้รับคำเตือนที่ไม่ถูกเลือก (ซึ่งสามารถระงับได้) เช่น <br> <code> myMatrix = (LinkedList <IntegerNode> []) LinkedList ใหม่ <?> [numRows]; </code>
Neon

5

นอกเหนือจากปัญหาทางไวยากรณ์แล้วดูเหมือนว่าแปลกสำหรับฉันที่จะใช้อาร์เรย์และรายการที่เชื่อมโยงเพื่อแสดงเมทริกซ์ เพื่อให้สามารถเข้าถึงเซลล์โดยพลการของเมทริกซ์คุณอาจต้องการอาร์เรย์จริงหรืออย่างน้อยก็ArrayListถือแถวเนื่องจากLinkedListต้องสำรวจรายการทั้งหมดจากองค์ประกอบแรกไปยังองค์ประกอบเฉพาะใด ๆ การO(n)ดำเนินการซึ่งตรงข้ามกับส่วนมาก เร็วขึ้นO(1)ด้วยArrayListหรืออาร์เรย์จริง

เนื่องจากคุณได้กล่าวถึงเมทริกซ์นี้มีความเบาบาง แต่บางทีวิธีที่ดีกว่าในการจัดเก็บข้อมูลก็คือแผนที่ของแผนที่โดยที่คีย์ในแผนที่แรกแสดงถึงดัชนีแถวและค่าของมันคือแผนที่แถวที่มีคีย์เป็นดัชนีคอลัมน์ โดยมีค่าเป็นคลาส IntegerNode ของคุณ ดังนั้น:

private Map<Integer, Map<Integer, IntegerNode>> myMatrix = new HashMap<Integer, Map<Integer, IntegerNode>>();

// access a matrix cell:
int rowIdx = 100;
int colIdx = 30;
Map<Integer, IntegerNode> row = myMatrix.get(rowIdx); // if null, create and add to matrix
IntegerNode node = row.get(colIdx); // possibly null

หากคุณต้องการที่จะสามารถสำรวจแถวเมทริกซ์โดยแถวที่คุณสามารถทำแผนที่ของแถวชนิดTreeMapและเช่นเดียวกันสำหรับ traversing คอลัมน์ในลำดับดัชนี แต่ถ้าคุณไม่จำเป็นต้องมีกรณีดังกล่าวจะเร็วกว่าHashMap TreeMapวิธีการช่วยเหลือในการรับและตั้งค่าเซลล์ตามอำเภอใจการจัดการค่าว่างที่ไม่ได้ตั้งค่าจะมีประโยชน์แน่นอน



3

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList[numRows];

การร่ายวิธีนี้ได้ผล แต่ยังคงทำให้คุณมีคำเตือนที่น่ารังเกียจ:

"ประเภทความปลอดภัย: นิพจน์ของประเภทรายการ [] ต้องการการแปลงที่ไม่ได้ตรวจสอบ .. "

การประกาศคลาสพิเศษสำหรับ Array of Lists:

class IntegerNodeList { private final List< IntegerNode > nodes; }

เป็นความคิดที่ชาญฉลาดในการหลีกเลี่ยงคำเตือน อาจจะดีกว่าเล็กน้อยคือการใช้อินเทอร์เฟซสำหรับมัน:

public interface IntegerNodeList extends List<IntegerNode> {}

แล้ว

List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];

รวบรวมโดยไม่มีคำเตือน

ไม่ได้ดูแย่เกินไปใช่ไหม


IntegerNodeList: คุณจะใช้คลาสอะไร ตัวอย่างเช่นคุณไม่สามารถกำหนด ArrayList <IntegerNode> ให้กับมันได้ คุณจะต้องขยาย ArrayList ด้วย ...
Hans-Peter Störr

ไม่จำเป็นต้องใช้อินเตอร์เฟส IntegerNodeList นอกการเริ่มต้นอาร์เรย์: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; สำหรับ (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = ArrayList ใหม่ <IntegerNode> (); }
user306708

1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];ปัญหานี้มีความละเอียดอ่อน แต่สำคัญ คุณสามารถเพียงใส่IntegerNodeListในอาร์เรย์ จะโยนmyMatrix[i] = new ArrayList<IntegerNode>(); ArrayStoreException
Radiodef

2
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

ไม่มีคำเตือนใด ๆ NetBeans 6.9.1, jdk1.6.0_24


1
ไม่มีคำเตือนจริง แต่ด้วย Java SE 6 Update 32 ของ Oracle ฉันได้รับข้อผิดพลาดในการคอมไพล์ "รายการประเภทไม่ใช่แบบทั่วไปไม่สามารถกำหนดพารามิเตอร์ด้วยอาร์กิวเมนต์ <String>" ได้ การลบอาร์กิวเมนต์ <String> ทำให้เกิดข้อผิดพลาดอื่น "Type mismatch: can't convert from LinkedList <String> to List"
Marco Lackovic

2

ไม่มีการสร้างอาร์เรย์ทั่วไปใน Java 1.5 (หรือ 1.6 เท่าที่ฉันสามารถบอกได้) ดูhttps://community.oracle.com/message/4829402


0

หากฉันทำสิ่งต่อไปนี้ฉันได้รับข้อความแสดงข้อผิดพลาดที่เป็นปัญหา

LinkedList<Node>[] matrix = new LinkedList<Node>[5];

แต่ถ้าฉันแค่ลบประเภทรายการในการประกาศดูเหมือนว่าจะมีฟังก์ชันที่ต้องการ

LinkedList<Node>[] matrix = new LinkedList[5];

คำประกาศทั้งสองนี้แตกต่างกันอย่างมากโดยที่ฉันไม่ทราบหรือไม่?

แก้ไข

อาฉันคิดว่าฉันพบปัญหานี้แล้ว

การวนซ้ำบนเมทริกซ์และการเริ่มต้นรายการใน for-loop ดูเหมือนจะใช้งานได้ แม้ว่าจะไม่เหมาะอย่างยิ่งกับโซลูชันอื่น ๆ ที่เสนอ

for(int i=0; i < matrix.length; i++){

    matrix[i] = new LinkedList<>();
}

0

คุณต้องมีอาร์เรย์ของ List ทางเลือกหนึ่งคือลอง:

private IntegerNode[] node_array = new IntegerNode[sizeOfYourChoice];

จากนั้นจัดnode_array[i]เก็บโหนดหัว (แรก) ของArrayList<IntegerNode>หรือLinkedList<IntegerNode>(การใช้งานรายการโปรดของคุณ)

ภายใต้การออกแบบนี้คุณจะสูญเสียวิธีการเข้าถึงโดยสุ่ม list.get(index)แต่จากนั้นคุณยังสามารถสำรวจรายการโดยเริ่มต้นด้วยที่เก็บโหนดหัว / กำปั้นในอาร์เรย์ชนิดปลอดภัย

นี่อาจเป็นตัวเลือกการออกแบบที่ยอมรับได้ขึ้นอยู่กับกรณีการใช้งานของคุณ ตัวอย่างเช่นฉันใช้การออกแบบนี้เพื่อแสดงรายการคำเสริมของกราฟในกรณีการใช้งานส่วนใหญ่จะต้องมีการข้ามผ่านรายการ adjacency สำหรับจุดยอดที่กำหนดแทนที่จะเข้าถึงโดยสุ่มจุดยอดบางจุดในรายการ

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