5.03_集合框架(set集合)

一、Set集合概述

  一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。

  在所有构造方法以及 addequalshashCode 方法的协定上,Set 接口还加入了其他规定,这些规定超出了从 Collection 接口所继承的内容。出于方便考虑,它还包括了其他继承方法的声明(这些声明的规范已经专门针对 Set 接口进行了修改,但是没有包含任何其他的规定)。

对这些构造方法的其他规定是(不要奇怪),所有构造方法必须创建一个不包含重复元素的 set(正如上面所定义的)。

注:如果将可变对象用作 set 元素,那么必须极其小心。如果对象是 set 中某个元素,以一种影响 equals 比较的方式改变对象的值,那么 set 的行为就是不确定的。此项禁止的一个特殊情况是不允许某个 set 包含其自身作为元素。

某些 set 实现对其所包含的元素有所限制。例如,某些实现禁止 null 元素,而某些则对其元素的类型所有限制。试图添加不合格的元素会抛出未经检查的异常,通常是 NullPointerExceptionClassCastException。试图查询不合格的元素是否存在可能会抛出异常,也可能简单地返回 false;某些实现会采用前一种行为,而某些则采用后者。概括地说,试图对不合格元素执行操作时,如果完成该操作后不会导致在 set 中插入不合格的元素,则该操作可能抛出一个异常,也可能成功,这取决于实现的选择。此接口的规范中将这样的异常标记为“可选”。

二、HashSet存储字符串并遍历  

    HashSet<String> hs = new HashSet<>(); //创建HashSet对象
    boolean b1 = hs.add("a");
    boolean b2 = hs.add("a"); //当向set集合中存储重复元素的时候返回为false
    hs.add("b");
    hs.add("c");
    hs.add("d");
    System.out.println(hs); //HashSet的继承体系中有重写toString方法
    System.out.println(b1);
    System.out.println(b2);

    for (String string : hs) { //只要能用迭代器迭代的,就可以使用增强for循环遍历
      System.out.println(string);
  }
}

三、自定义对象保证元素的唯一性  

    /**
      * @param args
      * Set集合,无索引,不可以重复,无序(存取不一致)
  */
      public static void main(String[] args) {
          //demo1();
        HashSet<Person> hs = new HashSet<>();
        hs.add(new Person("张三", 23));
        hs.add(new Person("张三", 23));
        hs.add(new Person("李四", 24));
        hs.add(new Person("李四", 24));
        hs.add(new Person("李四", 24));
        hs.add(new Person("李四", 24));

        //System.out.println(hs.size());
        System.out.println(hs);
    }

重写hashCode()equals方法      

    /*
      * 为什么是31?
      * 1,31是一个质数,质数是能被1和自己本身整除的数
      * 2,31这个数既不大也不小
      * 3,31这个数好算,2的五次方-1,2向左移动5位
      */
        @Override
        public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result + age;
          result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
      }
      @Override
      public boolean equals(Object obj) {
      if (this == obj) //调用的对象和传入的对象是同一个对象
        return true; //直接返回true
        if (obj == null) //传入的对象为null
        return false; //返回false
        if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码
          return false; //如果不是直接返回false
          Person other = (Person) obj; //向下转型
          if (age != other.age) //调用对象的年龄不等于传入对象的年龄
          return false; //返回false
          if (name == null) { //调用对象的姓名为null
          if (other.name != null) //传入对象的姓名不为null
          return false; //返回false
          } else if (!name.equals(other.name)) //调用对象的姓名不等于传入对象的姓名
          return false; //返回false
          return true; //返回true
        }

四、LinkedHashSet

  A.概述   

    具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)

此实现可以让客户免遭未指定的、由 HashSet 提供的通常杂乱无章的排序工作,而又不致引起与 TreeSet 关联的成本增加。使用它可以生成一个与原来顺序相同的 set 副本,并且与原 set 的实现无关:

五、运用代码 

  /**
    * @param args
    * LinkedHashSet
    * 底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象
    * 因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
  */
    public static void main(String[] args) {
      LinkedHashSet<String> lhs = new LinkedHashSet<>();
      lhs.add("a");
      lhs.add("a");
      lhs.add("a");
      lhs.add("a");
      lhs.add("b");
      lhs.add("c");
      lhs.add("d");

      System.out.println(lhs);
  }

 六、TreeSet集合

  A概述

    TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一
    * 当compareTo方法返回0的时候集合中只有一个元素
    * 当compareTo方法返回正数的时候集合会怎么存就怎么取
    * 当compareTo方法返回负数的时候集合会倒序存储

  B代码演示   

    public static void main(String[] args) {
      //demo1();
      //demo2();
      //demo3();
      //demo4();
      //需求:将字符串按照长度排序
      TreeSet<String> ts = new TreeSet<>(new CompareByLen()); //Comparator c = new CompareByLen();
      ts.add("aaaaaaaa");
      ts.add("z");
      ts.add("wc");
      ts.add("nba");
      ts.add("cba");

      System.out.println(ts);
    }

    public static void demo4() {
      TreeSet<Person> ts = new TreeSet<>();
      ts.add(new Person("zhangsan", 23));
      ts.add(new Person("lisi", 13));
      ts.add(new Person("wangwu", 33));
      ts.add(new Person("zhaoliu", 43));
      ts.add(new Person("aaaa", 53));

      System.out.println(ts);
    }

    public static void demo3() {
      TreeSet<Person> ts = new TreeSet<>();
      ts.add(new Person("李四", 13));
      ts.add(new Person("张三", 23));
      ts.add(new Person("王五", 43));
      ts.add(new Person("赵六", 33));

      System.out.println('张' + 0);
      System.out.println('李' + 0);
      System.out.println('王' + 0);
      System.out.println('赵' + 0);

      System.out.println(ts);
  }

    public static void demo2() {
      TreeSet<Person> ts = new TreeSet<>();
      ts.add(new Person("张三", 23));
      ts.add(new Person("李四", 13));
      ts.add(new Person("周七", 13));
      ts.add(new Person("王五", 43));
      ts.add(new Person("赵六", 33));

      System.out.println(ts);
}

    public static void demo1() {
      TreeSet<Integer> ts = new TreeSet<>();
      ts.add(3);
      ts.add(1);
      ts.add(1);
      ts.add(2);
      ts.add(2);
      ts.add(3);
      ts.add(3);

      System.out.println(ts);
  }

}


  class CompareByLen /*extends Object*/ implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) { //按照字符串的长度比较
      int num = s1.length() - s2.length(); //长度为主要条件
      return num == 0 ? s1.compareTo(s2) : num; //内容为次要条件
    }

}

原文地址:https://www.cnblogs.com/zyyzy/p/12440869.html