Set 接口

Set 接口

Set 集合的通用知识

  • Set 它类似一个罐子,程序可以把多个对象“丢进”Set 集合,Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败(add()方法会返回 false,且新元素不会被加入)。

  • Set接口是Collection的子接口,set接口没有提供额外的方法

  • Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法

  • 无序性:无序性 != 随机性(教室座位)。
    真正的无序性,指的是元素在底层存储的位置是无序的。

  • 说明:要求添加进Set中的元素所在的类,一定要重写equals()和hashCode()方法。

 Person1 p1 = new Person1("GG", 23);
 Person1 p2 = new Person1("GG", 23);
 //若没重写,则上面两者都能添加进去

HashSet(典型实现,主要使用类)

主要特点

  • HashSet 具有以下特点:
    • 不能保证元素的排列顺序
    • HashSet 不是线程安全的
    • 集合元素可以是 null
  • HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

注意:

如果需要把某个类的对象保存到 HashSet 集合中,重写这个类的 equals() 方法和 hashCode() 方法时,应该尽量保证两个对象通过 equals() 方法比较返回 true 时,它们的 hashCode() 方法的返回值也相等。

下面程序分别提供三个类A、B和C,它们分别重写了 equals()、hashCode() 两个方法的一个或全部,通过此程序可以让读者看到 HashSet 判断集合元素相同的标准:

package www.xq;

import java.util.HashSet;

/**
 * @author xqstart
 * @date 2018/10/23 - 7:55
 */


//类A的 equals() 方法总是返回 true,但没有重写其 hashCode() 方法
class A{

    public boolean equals(Object obj){
        return true;
    }
}

//类 B 的 hashCode() 方法总是返回 1,但是没有重写其 equals() 方法
class B{

    public int hashCode() {
        return 1;
    }
}

//类 C 的hashCode() 方法总是返回 2,且重写其 equals() 方法总是返回 true
 class C{

    public int hashCode(){
        return  2;
    }

    public boolean equals(Object obj){
        return true;
    }

}

public class TestHashSet {

    public static void main(String[] args) {

        HashSet books = new HashSet();
        //分别向 books 集合中添加两个 A 对象、两个 B 对象、两个 C 对象
        books.add(new A());
        books.add(new A());
        books.add(new B());
        books.add(new B());
        books.add(new C());
        books.add(new C());

        System.out.println(books);
    }

}

分析如下:
image

注意:

当向 HashSet 中添加可变对象时,必须十分小心。如果修改 HashSet 集合中的对象,有可能导致该对象与集合中的其他对象相等,从而导致 HashSet 无法准确访问该对象。

哈希算法

  • Set中的元素是如何存储的呢?使用了哈希算法。(学长讲解)

    • 当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算此对象的哈希值
      ,此哈希值决定了此对象在Set中的存储位置。若此位置之前没有对象存储,则这个对象直接存储到此位置。

    • 若此位置已有对象存储,再通过equals()比较这两个对象是否相同。如果相同,后一个对象就不能再添加进来。

image

LinkedHashSet

  • LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的

  • LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

  • 图解
    image

TreeSet

  1. 向TreeSet中添加的元素必须是同一个类的,否则会引发 ClassCastException

  2. 可以按照添加进集合中的元素的指定的顺序遍历。像String,包装类等默认按照从小到大的顺序遍历

  3. 当自定义类没有实现Comparable接口时,当向TreeSet中添加自定义类对象时,报 ClassCastException。

  4. 当向TreeSet中添加自定义类的对象时,有两种排序方法:
    ①自然排序(可操作类用)②定制排序(优先)

  5. 自然排序:要求自定义类实现(java.lang.Comparable)接口并重compareTo(Object obj)
    在此方法中,指明按照自定义类的哪个属性进行排序。

  6. 向TreeSet中添加元素时,首先按照compareTo(),一旦返回0,虽然仅是两个对象此
    属性值相同,但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来。

compareTo()与hashCode()以及equals()三者保持一致!???

各 Set 实现类的性能分析

  • HashSet 和 TreeSet 是 Set 的两个典型体现,到底该如何选择呢?

    • HashSet 的性能是比 TreeSet 好(特别是最常用的添加、查询元素等操作),因为 TreeSet 需要额外的红黑树算法来维护集合的次序。只有当需要一个保持排序的 Set 时,才应该使用 TreeSet,否则都应该使用 HashSet。
  • HashSet 还有一个子类:LinkedHashSet,对于普通的插入,删除操作,LinkedHashSet 比 HashSet 要略微慢一点,这是由维护链表所带来的额外开销造成的,但由于有了链表,遍历 LinkedHashSet 会更快。

  • EnumSet 是所有 Set 实现类中性能最好的,但它只能保存同一个枚举类的枚举值作为集合元素。

  • 必须指出,Set 的三个实现类 HashSet、TreeSet、EnumSet 都是线程不安全的。如果有多个线程同时访问一个 Set 集合,并且有超过一个线程修改了该 Set 集合,则必须手动保持该 Set 集合的同步性。通常可以通过 Collections 工具类的 synchronizedSortedSet 方法来“包装”该 Set 集合,此操作最好在创建时进行,以防止对 Set 集合的意外非同步访问。例如:

    SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值