2013-02-27 28 views
28

Nếu tôi viếtCollections.unmodifiableList và bản sao phòng thủ

List<Integer> a1 = Arrays.asList(1, 2, 3); 
List<Integer> a2 = Collections.unmodifiableList(a1); 

a2 là chỉ đọc nhưng nếu tôi viết

a1.set(0,10); 

sau đó a2 cũng được sửa đổi.

Nếu trong API nói:

Trả một cái nhìn unmodifiable của bộ sưu tập xác định. Phương pháp này cho phép các mô-đun cung cấp cho người dùng quyền truy cập "chỉ đọc" vào bộ sưu tập nội bộ .

thì, tại sao nếu tôi sửa đổi bộ sưu tập gốc thì bộ sưu tập sao chép đích được sửa đổi?

Có lẽ tôi đã hiểu sai ý nghĩa và nếu có cách nào để viết bản sao phòng thủ của bộ sưu tập đó?

+1

Nếu bạn muốn có một phiên bản unmodifiable của a1 sau đó bạn có thể sao chép a1 và làm cho rằng một danh sách unmodifiable. Sau đó, cập nhật a1 sẽ không ảnh hưởng a2. –

Trả lời

36

Có, bạn đã hiểu chính xác. Ý tưởng là đối tượng trả về bởi umodifiableCollection không thể thay đổi trực tiếp, nhưng có thể thay đổi thông qua các phương tiện khác (hiệu quả bằng cách thay đổi trực tiếp bộ sưu tập nội bộ).

Miễn là có thứ gì đó có quyền truy cập vào danh sách nội bộ, bộ sưu tập "không thể sửa đổi" có thể được thay đổi.

Đó là lý do tại sao bạn thường xây dựng một bộ sưu tập unmodifiable và chắc chắn rằng không có gì bao giờ có thể nhận được vào danh sách nội bộ:

Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3)); 

Vì không có gì bao giờ nhận được một tham chiếu đến List tạo ra bởi asList, đây là một bộ sưu tập thực sự không thể sửa đổi được.

Ưu điểm của phương pháp này là bạn không cần sao chép toàn bộ bộ sưu tập/danh sách gốc, tránh sử dụng bộ nhớ và công suất tính toán.

Guava cung cấp lớp ImmutableCollection (và các lớp con của nó như ImmutableList) cung cấp bộ sưu tập bất biến thực sự (thường bằng cách sao chép nguồn).

+0

'Arrays.asList()' đã trả về một danh sách kích thước cố định. Vậy tại sao chúng ta cần bổ sung trang trí nó bằng cách sử dụng 'Collections.unmodifiableList()'? Tôi thấy cả bạn và @assylias đã sử dụng cùng một thành ngữ. Bạn có thể giải thích dùm không? – Geek

+6

@Geek: Trong khi 'Arras.asList()' trả về một danh sách kích thước cố định, nó không trả về một danh sách không thể sửa đổi được. Bạn vẫn có thể thay đổi các phần tử bằng cách sử dụng 'set (int, T)'. 'Collections.unmodifiableList()' "sửa lỗi" "bằng cách không cho phép điều này. Nhưng trong bất kỳ mã thế giới thực nào, tôi có thể chỉ sử dụng ổi 'ImmutableList' (liên kết ở trên), vì viết ngắn hơn, rất rõ ràng và luôn đảm bảo rằng không có gì có thể" rò rỉ ". –

1

Ý tưởng là bạn không thể sửa đổi danh sách qua a2.

Sửa đổi danh sách a1 thực sự sẽ sửa đổi những gì bạn thấy trong a2 - đây là mục đích.

Chỉ cần không có một cách nào để truy cập vào danh sách a1, và bạn nên có những gì bạn muốn :)

1

API nói nó bộ sưu tập nội trong trường hợp của bạn bộ sưu tập là không nội

sự điểm là khi bạn có một danh sách riêng trong lớp một gettet cho danh sách đó, thì bạn có thể muốn người gọi của getter không thể sửa đổi danh sách trong trường hợp phù thủy bạn sẽ phải trả về một danh sách có thể điều chỉnh được. nếu không danh sách trả lại chỉ là một tham chiếu đến danh sách nội bộ/riêng tư của bạn và do đó nội dung của nó có thể được sửa đổi.

7

Có thể tôi đã hiểu sai ý nghĩa và nếu vậy cách viết một bản sao phòng thủ của bộ sưu tập đó là gì?

Thông thường, bạn sẽ sử dụng nó như vậy:

private List<Integer> a1 = Arrays.asList(1, 2, 3); 

public List<Integer> getUnmodifiable() { 
    return Collections.unmodifiableList(a1); 
} 

Một người nào đó gọi getUnmodifiable không có quyền truy cập vào nội bộ của lớp học của bạn (tức là họ không thể acces biến tin a1), sẽ không thể sửa đổi danh sách được trả lại.

+1

'Arrays.asList()' đã trả về một danh sách kích thước cố định. Vậy tại sao chúng ta cần bổ sung trang trí nó bằng cách sử dụng 'Collections.unmodifiableList()'? Tôi đang thiếu gì? – Geek

+3

Bạn không thể thêm vào a1 nhưng bạn có thể đặt bất kỳ mục nào thành mục khác. – assylias

+0

@assylias Trên thực tế bạn có thể sửa đổi nội bộ của các đối tượng trong danh sách, nhưng bạn không thể sử dụng phương thức set() để thay thế một đối tượng cũ bằng một đối tượng khác trong danh sách. – Sam003

0

a1a2 sẽ tham chiếu cùng một dữ liệu (bộ nhớ).

phần không thể sinh ra được, chỉ với a2 làm mục nhập.

hình ảnh nếu bạn đang đi qua a2 đến phương pháp mà bạn mong đợi phương pháp là không đáng tin cậy. các trường hợp như vậy a2 sẽ giúp.

tóm tắt, bạn không thể sửa đổi dữ liệu bằng cách sử dụng con trỏ a2.

1

Tuyên bố:

Collections.unmodifiableList(a1); 

trả về một wrapper qua bộ sưu tập ban đầu mà sửa đổi phương pháp ném UnsupportedOperationException.

Trình bao bọc được đọc qua, nghĩa là nếu bạn sửa đổi a1, các thay đổi sẽ phản ánh trên bộ sưu tập được gói a2.

+1

Thực ra bạn có thể sửa đổi nội bộ của các đối tượng trong danh sách, nhưng bạn không thể sử dụng phương thức set() để thay thế một đối tượng cũ bằng một đối tượng khác. – Sam003

0

Nếu quý vị cần danh sách unmodifiable và bất biến hay nói cách khác bản sao unmodifiable của danh sách nguồn mà không cần bất kỳ sự phụ thuộc vào các thư viện khác thử điều này:

Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList))) 

Collections.list() bản sao giá trị từ liệt kê nó.

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