Không thể tạo một mảng LinkedLists trong Java…?


102

Tôi đang làm việc trên một lớp ma trận thưa thớt cần sử dụng một mảng LinkedListđể lưu trữ các giá trị của ma trận. Mỗi phần tử của mảng (tức là mỗi LinkedList) đại diện cho một hàng của ma trận. Và, mỗi phần tử trong LinkedListmảng đại diện cho một cột và giá trị được lưu trữ.

Trong lớp của tôi, tôi có một khai báo của mảng là:

private LinkedList<IntegerNode>[] myMatrix;

Và, trong hàm tạo của tôi cho SparseMatrix, tôi cố gắng xác định:

myMatrix = new LinkedList<IntegerNode>[numRows];

Lỗi cuối cùng tôi nhận được là

Không thể tạo một mảng chung LinkedList<IntegerNode>.

Vì vậy, tôi có hai vấn đề với điều này:

  1. Tôi đang làm gì sai, và
  2. Tại sao kiểu được chấp nhận trong khai báo cho mảng nếu nó không thể được tạo?

IntegerNodelà một lớp mà tôi đã tạo. Và, tất cả các tệp lớp của tôi được đóng gói cùng nhau.

Câu trả lời:


64

Bạn không thể sử dụng tạo mảng chung chung. Đó là một lỗ hổng / tính năng của java generics.

Những cách không có cảnh báo là:

  1. Sử dụng Danh sách Danh sách thay vì Mảng Danh sách:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. Khai báo lớp đặc biệt cho Mảng danh sách:

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

19
Một giải pháp thay thế tốt hơn cho giải pháp thứ hai sẽ là: class IntegerNodeList extends List<IntegerNode> {}
kamasheto

Việc triển khai này quá chậm. Lấy phần tử [1000] [2000] (nodeLists.get (1000) .get (2000)) sẽ làm cho LinkedList lặp lại 3000 lần! Tránh LinkedList nếu bất kỳ ai có thể lập chỉ mục vào đó. ArrayList sẽ lập chỉ mục nhanh hơn, nhưng giải pháp của Fredrik nhìn chung tốt hơn.
Steve Zobell

142

Vì lý do nào đó, bạn phải ép kiểu và khai báo như sau:

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

Tôi đã nghiên cứu một vấn đề tương tự và đọc rằng quá trình truyền ở trên là một 'hack' rất phổ biến được sử dụng trên toàn bộ khung sưu tập.
luke

15
IMO, đây phải là câu trả lời được chọn. Tôi chưa thử nghiệm, nhưng tôi có cảm giác rằng phương pháp số 2 của Sergey tạo ra khá nhiều chi phí; và tôi TÍCH CỰC rằng số 1 làm được. Một danh sách không hiệu quả bằng một mảng theo một số cách mà tôi sẽ không trình bày chi tiết ở đây, nhưng tôi đã thực hiện các thử nghiệm và thấy sự chậm lại lớn khi sử dụng danh sách so với mảng. Sẽ nhanh hơn khi chỉ quản lý các mảng của riêng bạn và phân bổ lại chúng, hơn là thêm nội dung vào Danh sách.
Ricket,

@Ricket Tôi đồng ý, được lấy từ ibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter

4
Tôi vẫn nhận được cảnh báo "Loại an toàn: truyền không được chọn". Đối với tôi, giải pháp của Bob có vẻ sạch sẽ nhất.
Marco Lackovic

3
Trong JDK 7, phần trên đưa ra cảnh báo kiểu nguyên. Điều đó có thể được khắc phục bằng cách sử dụng loại <?> Không bị ràng buộc, nhưng bạn vẫn nhận được cảnh báo không được kiểm tra (có thể bị loại bỏ). ví dụ: <br> <code> myMatrix = (LinkedList <IntegerNode> []) LinkedList mới <?> [numRows]; </code>
Neon

5

Ngoài các vấn đề về cú pháp, tôi thấy lạ khi sử dụng một mảng và một danh sách liên kết để biểu diễn một ma trận. Để có thể truy cập các ô tùy ý của ma trận, bạn có thể muốn một mảng thực tế hoặc ít nhất là một mảng ArrayListđể giữ các hàng, vì LinkedListphải duyệt qua toàn bộ danh sách từ phần tử đầu tiên đến bất kỳ phần tử cụ thể nào, một O(n)phép toán, trái ngược với nhiều nhanh hơn O(1)với ArrayListhoặc một mảng thực tế.

Tuy nhiên, vì bạn đã đề cập đến ma trận này khá thưa thớt, có lẽ cách tốt hơn để lưu trữ dữ liệu là dưới dạng bản đồ của các bản đồ, trong đó một khóa trong bản đồ đầu tiên đại diện cho một chỉ mục hàng và giá trị của nó là một bản đồ hàng có các khóa là một chỉ mục cột , với giá trị là lớp IntegerNode của bạn. Như vậy:

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

Nếu bạn cần có thể duyệt từng hàng của ma trận, bạn có thể đặt bản đồ hàng loại a TreeMapvà tương tự để duyệt qua các cột theo thứ tự chỉ mục, nhưng nếu bạn không cần những trường hợp đó, HashMapthì nhanh hơn TreeMap. Tất nhiên, các phương thức của người trợ giúp để lấy và đặt một ô tùy ý, xử lý các giá trị null chưa đặt, tất nhiên sẽ hữu ích.


4
class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 

Bạn đã bỏ lỡ phần chung cho LinkedList.
Peter Wippermann 19/12/12

3

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

truyền theo cách này hoạt động nhưng vẫn để lại cho bạn một cảnh báo khó chịu:

"An toàn kiểu: Biểu thức của kiểu Danh sách [] cần chuyển đổi không được chọn .."

Khai báo một lớp đặc biệt cho Mảng danh sách:

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

là một ý tưởng thông minh để tránh cảnh báo. có thể đẹp hơn một chút là sử dụng một giao diện cho nó:

public interface IntegerNodeList extends List<IntegerNode> {}

sau đó

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

biên dịch mà không có cảnh báo.

trông không quá tệ, phải không?


IntegerNodeList: bạn sẽ sử dụng cái này với lớp nào? Ví dụ: bạn không thể gán ArrayList <IntegerNode> cho nó. Bạn cũng cần phải mở rộng ArrayList ...
Hans-Peter Störr

không cần sử dụng giao diện IntegerNodeList ngoài việc khởi tạo mảng: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }
user306708

1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];Điều này có một vấn đề tế nhị nhưng quan trọng. Bạn chỉ có thể đặt IntegerNodeListtrong mảng. myMatrix[i] = new ArrayList<IntegerNode>();sẽ ném ArrayStoreException.
Radiodef

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

Không có bất kỳ cảnh báo nào. NetBeans 6.9.1, jdk1.6.0_24


1
Đúng không có cảnh báo nhưng với Bản cập nhật Java SE 6 của Oracle 32, tôi gặp lỗi biên dịch "Danh sách kiểu không phải là chung; nó không thể được tham số hóa bằng các đối số <Chuỗi>". Loại bỏ đối số <Chuỗi> sẽ tạo ra một lỗi khác "Loại không khớp: không thể chuyển đổi từ LinkedList <Chuỗi> thành Danh sách".
Marco Lackovic


0

Nếu tôi làm như sau, tôi nhận được thông báo lỗi được đề cập

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

Nhưng nếu tôi chỉ xóa loại danh sách trong khai báo thì nó dường như có chức năng mong muốn.

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

Hai tuyên bố này có khác nhau đáng kể theo cách mà tôi không biết không?

BIÊN TẬP

Ah, tôi nghĩ tôi đang gặp phải vấn đề này.

Lặp lại ma trận và khởi tạo danh sách trong vòng lặp for dường như hiệu quả. Mặc dù nó không lý tưởng như một số giải pháp khác được cung cấp.

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

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

0

Bạn cần một mảng Danh sách, một cách thay thế là thử:

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

Sau đó, node_array[i]lưu trữ nút đầu (đầu tiên) của một ArrayList<IntegerNode>hoặc LinkedList<IntegerNode>(bất kỳ cách triển khai danh sách yêu thích của bạn).

Theo thiết kế này, bạn sẽ mất phương thức truy cập ngẫu nhiên list.get(index), nhưng sau đó bạn vẫn có thể duyệt qua danh sách bắt đầu bằng kho lưu trữ nút đầu / nắm tay trong mảng kiểu an toàn.

Đây có thể là một lựa chọn thiết kế có thể chấp nhận được tùy thuộc vào trường hợp sử dụng của bạn. Ví dụ: tôi sử dụng thiết kế này để đại diện cho một danh sách kề của đồ thị, trong hầu hết các trường hợp sử dụng, nó vẫn yêu cầu duyệt qua danh sách kề đối với một đỉnh nhất định thay vì truy cập ngẫu nhiên một số đỉnh trong danh sách.

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.