【JAVA SE】集合框架--HashSet(一)

HashSet实现了Set接口。在实际开发中HashSet是Set的实现类里使用频率最高的类。既然实现了Set接口,所以HashSet必然是不能放入重复元素的。

那么什么是“重复的元素”呢?

先看下面的例子

public static void main(String[] args) {
    HashSet set=new HashSet();
   String str1=new String("hello");
    String str2=new String("hello");
    set.add(str1);
    set.add(str2);
    System.out.println(set);
}

输出结果:


也就是说str1和str2被认为是重复的,接着看第二个例子


public class Person {
    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;
}

  public static void main(String[] args) {
      HashSet set=new HashSet();
/*      String str1=new String("hello");
      String str2=new String("hello");
      set.add(str1);
      set.add(str2);*/
      Person p1=new Person("zhangsan");
      Person p2=new Person("zhangsan");
      set.add(p1);
      set.add(p2);
      System.out.println(set);
  }

如果按照第一个例子的那么这里应该只输出一个“zhangsan”的内存地址


实际结果,输出了两个对象的内存地址,也就是说往Hashset中添加两个元素成功了,被认为是不同的元素。下面看下源码:

/**
 * Adds the specified element to this set if it is not already present.
 * More formally, adds the specified element <tt>e</tt> to this set if
 * this set contains no element <tt>e2</tt> such that
 * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
 * If this set already contains the element, the call leaves the set
 * unchanged and returns <tt>false</tt>.
 *
 * @param e element to be added to this set
 * @return <tt>true</tt> if this set did not already contain the specified
 * element
 */
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

官方的注释可以解释成:add方法会先调用插入对象的hashCode方法 比较hashCode值是否相同,如果相同则不插入;如果hashCode值不同,再调用插入对象的Equals方法,如果equals返回true则不插入,反之则插入。

根据官方的解释已经可以明白为什么两个例子看似相同,而结果却不同了 ,因为Person类和String类的equals、hashCode方法实现并不同。我们知道String类重写了 Object类的quals、hashCode方法,而Person类并没有重写也就继承了Object类的两个方法。

此篇主要讲解Hashset,关于Object类的源码就不看了,直接说下结论


Object的equals 方法
自反性  x.equals(x)应该返回true
对称性  如果x.equals(y)为真,那么 y.equals(x)为真   
传递性  x.equals(y)为true,并且y.equals(z)为true ,x.equals(z)为true
一致性  如果x.equals(y)为真 ,那么第二次比较直到第n此比较都应为真,在x,y没有被修改的情况下

非空性  对于任意的非空引用x x.equals(null)应返回false

Object 类的hashCode方法
1.在一次 java应用程序的调用中,对于同一个对象调用多次hashCode方法,应该返回相同的值(前提是对象没有被改变)
2.对于两个对象来说如果使用equals方法比较返回true,那么两个对象的hasCode值一定是相同的
3.如果两个对象equals返回false,不要求两个hashCode 值一定不同

4.对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址)

第二个例子中p1,p2为两个对象实例,必然内存地址是不同的,所以hashCode返回false,元素直接被插入进去。下面我们在Person类中重写hashCode方法和equals方法

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return Objects.equals(name, person.name);
}

@Override
public int hashCode() {
    return Objects.hash(name);
}
再次运行main方法,打印出的set中只有一个对象的内存地址

ps:欢迎讨论,指正 qq:29138386

原创,转载请声明,谢谢







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值