2010-11-15 34 views
9

Tôi là người mới sử dụng Java.Java - cách tốt nhất để triển khai mảng đối tượng có kích thước động

Tôi phải triển khai một mảng các đối tượng thay đổi kích thước trong khi thực thi.

Mã tôi đang viết cũng sẽ được chuyển trên Android.

Theo kinh nghiệm của bạn, lớp học tốt nhất để thực hiện điều đó là gì?

Cảm ơn,
Dan

+2

Khó trả lời mà không biết yêu cầu. Hãy xem http://download.oracle.com/javase/tutorial/collections/index.html và xem cái nào phù hợp với hóa đơn. –

+0

Tại sao không sử dụng API trong ArrayList, ví dụ? – dacwe

Trả lời

21

Java có khả năng mẫu không đầy đủ. Miễn là bạn muốn một mảng các đối tượng, thì ArrayList<T> là tốt. Đối với nguyên thủy, nó khủng khiếp.

Giả sử bạn có một hệ thống phân cấp của các đối tượng mà bạn muốn đưa vào một danh sách, ArrayList là lý tưởng:

ArrayList<Vehicle> vehicles = new ArrayList<Vehicle>(); 

vehicles.add(new Car(...)); 
vehicles.add(new Truck(...)); 

Tôi giả định trong ví dụ trên mà xe là lớp cơ sở, và xe hơi và xe tải là các lớp con.

Mặt khác, nếu bạn muốn danh sách các số, Java sẽ không hiệu quả cao. Mỗi đối tượng là một tham chiếu (thực sự là một con trỏ 4 byte) đến một đoạn 12 byte bộ nhớ, cộng với những gì bạn đang thực sự sử dụng. Vì ArrayList không thể áp dụng cho int, điều này có nghĩa là việc tạo danh sách các số có nghĩa là:

  1. Tạo danh sách Số nguyên, trình bao bọc đối tượng cho int.
  2. Chuyển đổi các đối tượng mỗi lần bạn lấy ra một số. Điều này được thực hiện tự động những ngày này, nhưng phải mất thời gian.
  3. Khởi tạo bộ nhớ gấp 5 lần khi cần.

Vì vậy, nếu bạn đang xử lý các khối dữ liệu thô sơ (int, float, double), bạn có thể đáng giá khi viết phiên bản ArrayList của riêng mình. Điều này đặc biệt quan trọng khi dữ liệu lớn và nền tảng nhỏ (như một điều Android cầm tay).

Hãy so sánh này:

ArrayList<Integer> list = new ArrayList<Integer>(); 
for (int i = 0; i < 1000000; i++) 
    list.add(i): 

tới:

public class IntArray { 
private int[] data; 
private int used; 
private void grow() { 
// implement code to make data double in size here... 
} 
public IntArray(int size) { 
    data = new int[size]; 
    used = 0; 
} 

public void add(int i) { 
    if (i >= data.length) grow(); 
    data[used++] = i; 
} 
} 

IntArray list2 = new IntArray(1000000); 
for (int i = 0; i < 1000000; i++) 
    list2.add(i); 

Lần cuối cùng tôi benchmarked nó, việc sử dụng tối ưu của danh sách nguyên thủy là hơn 10 lần nhanh hơn so với việc sử dụng phải thừa nhận là không tối ưu của ArrayList . Để công bằng hơn, hãy phân bổ trước danh sách mảng để có kích thước phù hợp - nó vẫn còn chậm hơn.

LinkedList chỉ đáng giá nếu bạn đang chèn vào đầu hoặc giữa danh sách. Nếu danh sách của bạn đang được xây dựng bằng cách thêm vào cuối, ArrayList sẽ triệt để thống trị LinkedList. Vì vậy, đối với một danh sách điển hình của các đối tượng mà bạn đang xây dựng theo thứ tự, ArrayList là những gì bạn đang tìm kiếm. Đối với một danh sách lớn các nguyên thủy như int hoặc double, hãy viết danh sách của riêng bạn.

+0

Trong khi sử dụng nơi 'LinkedList' tốt nhất có thể hiếm khi so sánh với' ArrayList', chúng tồn tại và 'LinkedList' có thể thực hiện _significantly_ tốt hơn trong chúng. Việc sử dụng danh sách giống như một danh sách là một ví dụ ... việc loại bỏ từ phía trước của một 'ArrayList' là cực kỳ tốn kém so với' LinkedList'. Xem [this] (http://blog.publicobject.com/2010/07/caliper-confirms-reality-linkedlist-vs.html) và [this] (http://microbenchmarks.appspot.com/run/[email protected] gmail.com/com.publicobject.blog.ListAsQueueBenchmark). – ColinD

+0

@Colin, Sử dụng một ArrayList ngây thơ thay vì một LinkedList thực sự có thể là một điều xấu. Nhưng nếu bạn muốn một hàng đợi nhanh hơn, thì tôi sẽ đặt cược việc thực hiện hàng đợi hình tròn với đầu/đuôi được chỉ định sẽ đánh bại LinkedList bằng một biên độ khổng lồ - ngay cả khi bạn có thể tăng trưởng khi/nếu bạn cần, trường hợp trung bình sẽ chỉ đặt các đối tượng trong một danh sách đã tồn tại. Có, chèn vào đầu của một ArrayList là tốn kém. – Dov

2

Bạn nên quen thuộc tự của bạn với collection framework trong java. Bạn có những thứ như Set, List, Map, SortedSets, vv… Mà có thể là cấu trúc dữ liệu thực sự hữu ích.

0

Tùy thuộc vào những gì bạn sẽ sử dụng.

Nếu bạn có một mảng thay đổi kích thước thường xuyên, thì tôi khuyên bạn nên sử dụng ArrayList hoặc thứ khác từ collection framework (tùy thuộc vào những gì bạn sẽ sử dụng nó).

Nếu bạn tuy nhiên có một mảng mà thay đổi kích thước rất thường xuyên nhưng được đọc thường xuyên, nó có lẽ sẽ nhanh hơn để sử dụng một mảng bình thường và sau đó thay đổi kích thước khi cần thiết thay vì

Arrays.copyOf(array, newSize); 

Hy vọng nó sẽ giúp! :)

+0

Trong khi các mảng nguyên thủy là tốt nhất, đôi khi không có lý do chính đáng nào để sử dụng một mảng các đối tượng trong Java. "nó có lẽ sẽ nhanh hơn" ... tối ưu hóa sớm. – ColinD

+0

Sử dụng một lớp nguyên thủy khác với việc viết bằng các mảng được mã hóa cứng. Và quá nhiều sự chú ý được trả tiền để tránh "tối ưu hóa sớm" hơn là chỉ đơn giản là biết những gì là hiệu quả, và làm nó như là một vấn đề của khóa học. Nó chỉ là dễ dàng để viết mã tốt trong hầu hết các trường hợp như là mã xấu. Đôi khi, phải mất nhiều công việc hơn một chút, và đó là khi bạn có thể suy nghĩ về việc đó sau này. – Dov

+0

@Dov: Tôi chắc chắn đồng ý rằng khi đó là vấn đề làm điều gì đó rõ ràng kém hơn so với làm điều gì đó đúng và có khả năng sẽ hoạt động tốt hơn cho cùng một nỗ lực, nó không phải là tối ưu hóa sớm để làm điều đúng. Nhưng mảng kém hơn nhiều cách và sử dụng chúng trực tiếp gần như chắc chắn sẽ tạo ra nhiều công việc hơn để làm những việc đơn giản và làm cho mã khó hiểu hơn, và có khả năng sẽ không truyền đạt bất kỳ cải tiến hiệu suất nào quan trọng cho tất cả, nhưng thấp nhất -ống của mã. Đó là lý do tại sao tôi sẽ xem xét tối ưu hóa sớm này. – ColinD

Các vấn đề liên quan