2013-07-05 50 views
7

Trực tiếp từ this java doc:Bản đồ chứa chính nó như một giá trị;

Một trường hợp đặc biệt của lệnh cấm này là nó không được phép cho một bản đồ chứa chính nó như là một chìa khóa. Mặc dù bản đồ cho phép bản đồ là chính nó là một giá trị, nhưng bạn nên lưu ý: các phương thức equals và hashCode không còn được xác định rõ trên bản đồ như vậy nữa.

Tại sao hashcode và bằng không còn được xác định rõ trên bản đồ như vậy?

Xin cảm ơn trước.

+2

nếu tôi nhớ chính xác phương pháp bằng kiểm tra nếu nội dung của bản đồ bằng nhau. và điều này được thực hiện bằng cách sử dụng phương thức equals của nội dung, tức là bản thân bản đồ. Tôi khá chắc chắn chúng tôi kết thúc với một StackOverflowError –

+0

Có thể là cách một bản đồ bằng chức năng trông? có lẽ nó sẽ gây ra một vòng lặp vô hạn? Chỉ cần một ý nghĩ – Kevin

+0

@MarcoForberg Nếu tôi nhớ chính xác, cách tốt nhất là kiểm tra xem đối tượng mà bạn so sánh có thực sự là chính bạn và trả về true ngay lập tức nếu có. –

Trả lời

2

Các trích dẫn đầy đủ của đoạn từ Documents Java là:

Lưu ý: cẩn thận phải được thực hiện nếu đối tượng có thể thay đổi được sử dụng như phím bản đồ . Hành vi của bản đồ không được xác định nếu giá trị của một đối tượng được thay đổi theo cách ảnh hưởng đến bằng so sánh trong khi đối tượng là một khóa trong bản đồ. Trường hợp đặc biệt của lệnh cấm này là nó không được phép cho một bản đồ để chứa chính nó như là một chìa khóa.Trong khi nó được phép cho một bản đồ để chứa chính nó như là một giá trị, cực kỳ thận trọng được khuyên: các phương thức equals và hashCode không còn được xác định rõ trên bản đồ như vậy nữa.

Phương thức AbstractMap.hashCode() sử dụng mã băm của cặp giá trị khóa trong bản đồ để tính toán mã băm. Do đó mã băm được tạo ra từ phương thức này sẽ thay đổi mỗi khi bản đồ được sửa đổi.

Mã băm được sử dụng để tính toán nhóm để đặt mục nhập mới. Nếu bản đồ được sử dụng như một khóa trong chính nó thì thùng được tính sẽ khác nhau mỗi khi một mục mới được cập nhật/xóa/sửa đổi. Do đó, việc tra cứu trong tương lai với bản đồ dưới dạng khóa sẽ rất có thể thất bại bởi vì một thùng khác biệt được tính từ mã băm. Các lần đặt trong tương lai có thể không phát hiện được khóa đã có trong bản đồ và sau đó cho phép nhiều mục có cùng khóa (nhưng trong các nhóm khác nhau)

1

Hai bản đồ bằng nhau nếu cùng một khóa ánh xạ với cùng một giá trị. (Trong một số triển khai.) Vì vậy, để kiểm tra bình đẳng, bình đẳng của mỗi thành viên cần được kiểm tra.

Do đó, nếu bản đồ chứa chính nó, bạn sẽ nhận được một lần truy cập vô hạn kiểm tra bình đẳng.

Điều tương tự cũng xảy ra đối với băm, vì chúng có thể được tính phụ thuộc vào giá trị băm của các phần tử trong bản đồ.

Ví dụ:

Map<Int, Object> ma; 
Map<Int, Object> mb; 
Map<Int, Object> mc; 

ma.put(1, ma); 
ma.put(2, mb); 
mc.put(1, ma); 
mc.put(2, mb); 

Là một con người, chúng ta có thể thấy mamc đều bình đẳng từ định nghĩa. Một máy tính sẽ thấy 2 bản đồ trên mb (một bản đồ trống) trong cả hai bản đồ, đó là tốt. Nó sẽ thấy 1 bản đồ trên bản đồ khác trong cả mc và ma. Nó sẽ kiểm tra xem các bản đồ này có bình đẳng không. Để xác định điều này, nó sẽ kiểm tra lại nếu hai giá trị cho 1 bằng. Và một lần nữa.

Lưu ý rằng đây không phải là trường hợp cho tất cả các triển khai. Một số triển khai có thể kiểm tra sự bình đẳng trên vị trí trong bộ nhớ đối tượng được lưu, ... Nhưng mọi kiểm tra đệ quy sẽ lặp vô hạn.

5

Các AbstractMap.equals là một phần liên quan được sử dụng bởi hầu hết các trường Map:

  Iterator<Entry<K,V>> i = entrySet().iterator(); 
      while (i.hasNext()) { 
       Entry<K,V> e = i.next(); 
       K key = e.getKey(); 
       V value = e.getValue(); 
       if (value == null) { 
        if (!(m.get(key)==null && m.containsKey(key))) 
         return false; 
       } else { 
        if (!value.equals(m.get(key))) // would call equals on itself. 
         return false; 
       } 
      } 

Thêm bản đồ như một giá trị sẽ cho kết quả trong một vòng lặp vô hạn.

+1

Câu lệnh đầu tiên trong phương thức equals() là ** if (o == this) trả về true; ** Tôi nghĩ rằng điều này sẽ ngăn chặn vòng lặp infinate, vì nó sẽ trở lại ngay lập tức và không bao giờ thực thi mã mà bạn đã đánh dấu. –

+0

Chết tiệt bạn đúng. Câu trả lời cần được bỏ đánh dấu. Có lẽ đó là bởi vì nó như vậy thực hiện phụ thuộc mà họ đã không xác định nó không khuyên bạn nên nó. – ssindelar

+0

bạn cũng có thể tạo ra một vấn đề bằng cách tạo hai bản đồ, đặt một bản đồ vào bản đồ kia và gọi equals trên một bản đồ với nhau như tham số. hoặc bạn chỉ cần đặt một bản đồ vào chính nó và gọi hashcode() –

0

Để cố gắng giải thích nó:

Các bằng phương pháp sẽ lặp trên cả Maps và gọi các bằng phương pháp của mỗi khoá và giá trị của bản đồ. Vì vậy, nếu bản đồ chứa chính nó, bạn sẽ tiếp tục gọi phương thức equals vô thời hạn.

Điều tương tự cũng xảy ra với mã băm.

Nguồn: mã nguồn của lớp AbstractMap