Set 的主要实现类:HashSet

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Set 的主要实现类:HashSet相关的知识,希望对你有一定的参考价值。

  • Set 可以存null
  • Set 下的方法基本上就是 Collection 中的
  • Set 的“无序性” ≠ “随机性”:“无序性”是指元素在内存中存储的位置是无序的,但是位置是确定的,并不会变化
  • Set 是不可重复的(使用哈希算法存储)

关于以上几点的说明:
  1. public class TestSet {
  2. @Test
  3. public void TestHashSet() {
  4. Set set1 = new HashSet();
  5. set1.add(null);// 可以存null
  6. set1.add(1);
  7. set1.add(2);
  8. set1.add(new String("A"));
  9. set1.add(new String("A"));// 不可重复性(依赖于 equals()和 hashCode()方法)
  10. set1.add("B");
  11. System.out.println(set1);// [null, 1, A, 2, B]
  12. Set set2 = new HashSet();
  13. set2.add(2);
  14. set2.add(null);
  15. set2.add("B");
  16. set2.add(1);
  17. set2.add("A");
  18. System.out.println(set2);// [null, 1, A, 2, B],无序性
  19. }
  20. }

关于不可重复性的进一步说明:
对象存储可视为先调用 hashCode()方法,若当前的哈希值对应的内存位置已经有对象了(已存在与当前方法调用者的哈希值相同的对象),则再比较 equals()方法,而且要求此时的 equals()方法也必须返回 true ,若返回 false 则都存储(不建议如此)。
事实上,我们要求 hashCode()方法能够在使用 equals()方法比较对象返回 false 的情况下算出不同的哈希值,如果出现 equals()方法返回 false 而算出相同的哈希值的情况,说明该 hashCode()方法设计的不好。
另外,两个实际相同的对象也不应算出不一样的哈希值(此时Set中会有实际上的“重复”的元素),这同样需要避免。
如下代码说明了这一问题:
  1. public class TestSet2 {
  2. public static void main() {
  3. Set set = new HashSet();
  4. set.add(new Person1("aa"));
  5. set.add(new Person1("aa"));
  6. set.add(new Person2("aa"));
  7. set.add(new Person2("aa"));// Person2 没有重写 hashCode()方法,此时调用的是 Object类定义的hashCode()方法,算出哈希值不一样,所以可以存储
  8. System.out.println(set);// [Person2 [name=aa], Person2 [name=aa],Person1 [name=aa]]
  9. }
  10. }
  11. class Person1 {
  12. private String name;
  13. @Override
  14. public String toString() {
  15. return "Person1 [name=" + name + "]";
  16. }
  17. public Person1(String name) {
  18. super();
  19. this.name = name;
  20. }
  21. @Override
  22. public int hashCode() {
  23. final int prime = 31;
  24. int result = 1;
  25. result = prime * result + ((name == null) ? 0 : name.hashCode());
  26. return result;
  27. }
  28. @Override
  29. public boolean equals(Object obj) {
  30. if (this == obj)
  31. return true;
  32. if (obj == null)
  33. return false;
  34. if (getClass() != obj.getClass())
  35. return false;
  36. Person1 other = (Person1) obj;
  37. if (name == null) {
  38. if (other.name != null)
  39. return false;
  40. } else if (!name.equals(other.name))
  41. return false;
  42. return true;
  43. }
  44. }
  45. class Person2 {
  46. private String name;
  47. public Person2(String name) {
  48. super();
  49. this.name = name;
  50. }
  51. @Override
  52. public String toString() {
  53. return "Person2 [name=" + name + "]";
  54. }
  55. @Override
  56. public boolean equals(Object obj) {
  57. if (this == obj)
  58. return true;
  59. if (obj == null)
  60. return false;
  61. if (getClass() != obj.getClass())
  62. return false;
  63. Person2 other = (Person2) obj;
  64. if (name == null) {
  65. if (other.name != null)
  66. return false;
  67. } else if (!name.equals(other.name))
  68. return false;
  69. return true;
  70. }
  71. }

总之,我们应要求 hashCode()方法与 equals()方法一致,直接用 eclipse 重写就行:技术分享

关于Set的底层存储:
先调用 hashCode()方法,若哈希值不一样,则存储,若一样,则调用 equals()方法比较,若返回 true 不存储,返回 false 则存储(应避免)。




以上是关于Set 的主要实现类:HashSet的主要内容,如果未能解决你的问题,请参考以下文章

Java学习笔记5.3.1 Set接口 - HashSet类

Java集合框架 Set接口实现类--HashSet的使用

Set接口HashSet实现类

深入浅出的分析 Set集合

Set的常用实现类HashSet和TreeSet

38各Set实现类的性能分析