Việc thêm một giá trị trùng lặp vào Hashset / HashMap có thay thế giá trị trước đó không


137

Vui lòng xem xét đoạn mã dưới đây:

HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)

hs.size()sẽ cho 1 vì HashSetkhông cho phép trùng lặp nên chỉ có một phần tử sẽ được lưu trữ.

Tôi muốn biết nếu chúng ta thêm phần tử trùng lặp, thì nó có thay thế phần tử trước đó hay đơn giản là nó không thêm nó?

Ngoài ra, những gì sẽ xảy ra sử dụng HashMapcho trường hợp tương tự?

Câu trả lời:


246

Trong trường hợp HashMap, nó thay thế giá trị cũ bằng giá trị mới.

Trong trường hợp HashSet, mục không được chèn.


1
Không chắc chắn những gì tôi đang thiếu, nhưng mã nguồn dường như chỉ ra điều khác? Tôi thấy rằng họ không kiểm tra mặt sau HashMapđể xem keycó tồn tại trước khi gọi putvào mặt sau mapkhông?
Mystarrocks

10
@mystarrocks: Chìa khóa là yếu tố của Setvà không bao giờ được thay thế bởi put()hoạt động.
Keppil

1
ah tôi hiểu rồi Tôi hiểu rằng khóa là thành phần của Set, nhưng chỉ nhận ra rằng put()sẽ chỉ ghi đè giá trị chứ không phải khóa. Trong trường hợp này, đó là cùng một giá trị được đặt cùng với khóa một lần nữa, điều này có thể hoặc không thể tốt hơn là kiểm tra xem khóa có tồn tại hay không. Dù bằng cách nào, tôi hiểu làm thế nào nó hoạt động.
Mystarrocks

Chỉ tò mò, tại sao HashMap và Hashset lại chọn như vậy?
Helin Wang

@HelinWang: Tôi không nghĩ nó đã được lên kế hoạch, tôi nghĩ nó chỉ là một hiệu ứng của HashSetviệc được thực hiện dưới dạng a HashMap. Khó biết mặc dù, trừ khi bạn là một trong những nhà phát triển của các lớp.
Keppil

47

Điều đầu tiên bạn cần biết là HashSethoạt động như một Set, có nghĩa là bạn thêm đối tượng của mình trực tiếp vào HashSetvà nó không thể chứa các bản sao. Bạn chỉ cần thêm giá trị của bạn trực tiếp vào HashSet.

Tuy nhiên, HashMaplà một Maploại. Điều đó có nghĩa là mỗi khi bạn thêm một mục, bạn thêm một cặp khóa-giá trị.

Trong HashMapbạn có thể có các giá trị trùng lặp, nhưng không trùng lặp các khóa. Trong HashMapmục mới sẽ thay thế cái cũ. Các mục gần đây nhất sẽ được trong HashMap.

Hiểu liên kết giữa HashMap và Hashset:

Hãy nhớ rằng, HashMapkhông thể có các khóa trùng lặp. Phía sau hiện trường HashSetsử dụng a HashMap.

Khi bạn cố gắng thêm bất kỳ đối tượng nào vào một HashSet, mục nhập này thực sự được lưu trữ dưới dạng một khóa trong HashMap- tương tự HashMapđược sử dụng đằng sau cảnh HashSet. Vì cơ sở này HashMapcần một cặp giá trị khóa, nên một giá trị giả được tạo cho chúng tôi.

Bây giờ khi bạn cố gắng chèn một đối tượng trùng lặp khác vào cùng HashSet, nó sẽ lại cố gắng chèn nó làm chìa khóa HashMapnằm bên dưới. Tuy nhiên, HashMapkhông hỗ trợ trùng lặp. Do đó, HashSetvẫn sẽ dẫn đến chỉ có một giá trị của loại đó. Như một lưu ý phụ, đối với mọi khóa trùng lặp, vì giá trị được tạo cho mục nhập của chúng tôi trong Hashset là một số giá trị ngẫu nhiên / giả, khóa này hoàn toàn không được thay thế. nó sẽ bị bỏ qua khi loại bỏ khóa và thêm lại cùng một khóa (giá trị giả là như nhau) sẽ không có ý nghĩa gì cả.

Tóm lược:

HashMapcho phép trùng lặp values, nhưng không keys. HashSetkhông thể chứa các bản sao.

Để biết liệu việc bổ sung đối tượng có hoàn thành thành công hay không, bạn có thể kiểm tra booleangiá trị được trả về khi bạn gọi .add() và xem liệu nó có trả về truehay không false. Nếu nó trở lại true, nó đã được chèn vào.


HashMap allows duplicate valuesHashMap thay thế giá trị cũ bằng giá trị mới.
Alex78191

20

Các tài liệu khá rõ ràng về điều này: HashSet.add không thay thế:

Thêm phần tử được chỉ định vào bộ này nếu nó chưa có sẵn. Chính thức hơn, thêm phần tử e đã chỉ định vào tập hợp này nếu tập hợp này không chứa phần tử e2 sao cho (e == null? E2 == null: e.equals (e2)). Nếu bộ này đã chứa phần tử, cuộc gọi sẽ giữ nguyên bộ và trả về false.

Nhưng sẽ thay thế:HashMap.put

Nếu bản đồ trước đây chứa ánh xạ cho khóa, giá trị cũ sẽ được thay thế.


4

Đó là trường hợp của Hashset, nó KHÔNG thay thế nó.

Từ các tài liệu:

http://docs.oracle.com/javase/6/docs/api/java/util/Hashset.html#add(E )

"Thêm phần tử được chỉ định vào tập hợp này nếu nó chưa có sẵn. Chính thức hơn, thêm phần tử được chỉ định e vào tập hợp này nếu tập hợp này không chứa phần tử e2 sao cho (e == null? E2 == null: e.equals ( e2)). Nếu bộ này đã chứa phần tử, cuộc gọi sẽ giữ nguyên bộ đó và trả về false. "


1

Sửa lỗi cho tôi nếu tôi sai nhưng điều bạn đang gặp phải là với các chuỗi, "Hi" == "Hi" không phải lúc nào cũng đúng (vì chúng không nhất thiết phải là cùng một đối tượng).

Lý do bạn nhận được câu trả lời là 1 vì JVM sẽ sử dụng lại các đối tượng chuỗi nếu có thể. Trong trường hợp này, JVM đang sử dụng lại đối tượng chuỗi và do đó ghi đè lên mục trong Hashmap / Hashset.

Nhưng bạn không đảm bảo hành vi này (vì nó có thể là một đối tượng chuỗi khác có cùng giá trị "Hi"). Hành vi bạn thấy chỉ là do tối ưu hóa của JVM.


0

Trước tiên, bạn cần kiểm tra phương thức put trong Hash map vì Hashset được sao lưu bởi HashMap

  1. Khi bạn thêm giá trị trùng lặp, hãy nói Chuỗi "Một" vào Hashset,
  2. Một mục ("một", PRESENT) sẽ được chèn vào Hashmap (đối với tất cả các giá trị được thêm vào tập hợp, giá trị sẽ là "HIỆN TẠI" nếu thuộc loại Object)
  3. Hashmap thêm mục nhập vào Bản đồ và trả về giá trị, trong trường hợp này là "HIỆN TẠI" hoặc null nếu Mục nhập không có ở đó.
  4. Phương thức thêm của Hashset sau đó trả về true nếu giá trị được trả về từ Hashmap bằng null nếu không sai có nghĩa là một mục đã tồn tại ...

0

Nói cách khác: Khi bạn chèn một cặp khóa-giá trị vào HashMap, nơi khóa đã tồn tại (theo nghĩa là hashvalue () cho cùng một giá trị und bằng () là đúng, nhưng hai đối tượng vẫn có thể khác nhau theo nhiều cách ), khóa không được thay thế nhưng giá trị bị ghi đè. Khóa này chỉ được sử dụng để lấy hashvalue () và tìm giá trị trong bảng với nó. Vì Hashset sử dụng các khóa của HashMap và đặt các giá trị tùy ý không thực sự quan trọng (đối với người dùng), do đó, các yếu tố của Bộ không được thay thế.


0

HashMapvề cơ bản chứa Entrycái nào sau đó chứa Key(Object)Value(Object). Bên trong HashSetHashMapHashMapthay thế các giá trị như một số bạn đã chỉ..nhưng nó có thực sự thay thế các khóa không ??? Không .. và đó là mẹo ở đây. HashMapgiữ giá trị của nó là khóa trong cơ sở HashMapvà giá trị chỉ là một đối tượng giả. Vì vậy, nếu bạn cố gắng đặt lại cùng một Giá trị trong HashMap (Khóa trong Bản đồ cơ bản). Nó chỉ thay thế giá trị giả chứ không phải Khóa (Giá trị cho Hashset).

Nhìn vào đoạn mã dưới đây cho Lớp Hashset:

public boolean  [More ...] add(E e) {

   return map.put(e, PRESENT)==null;
}

Ở đây e là giá trị cho Hashset nhưng khóa cho map.and khóa không bao giờ được thay thế. Hy vọng tôi có thể xóa sự nhầm lẫn.

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.