天天看點

【Java】集合.Set接口

文章目錄

  • ​​集合.Set接口​​
  • ​​一、Set接口:HashSet​​
  • ​​二、Set接口:SortedSet、TreeSet​​
  • ​​2.1 Comparable接口​​
  • ​​2.2 單獨編寫一個比較器​​
  • ​​2.3 匿名内部類(不推薦,隻能使用一次)​​

集合.Set接口

一、Set接口:HashSet

1.HashSet 底層實際上是一個HashMap(是以在許多方面HashMap與HashSet相似,可以進行比較),HashMap底層采用了哈希表資料結構

2.哈希表又叫做散清單

哈希表是一個數組,每一個元素是一個單向連結清單。

每個單向連結清單都有一個獨一無二的hash值,代表數組上的下标。

在某個單向連結清單中的每一個節點上的hash值都是相等的。

hash值實際上是key調用hashCode方法,通過"hash function"轉換成的值。

3.向哈希表中添加元素:

  • 先調用被存儲的key的hashCode方法,經過某個算法得出hash值:
  • a、已知哈希表中不存在該值,則直接加入元素
  • b、已知哈希表中存在該值,繼續調用key之間的equals方法:
  • 傳回 ​

    ​true​

    ​ , 放棄添加該元素
  • 傳回 ​

    ​false​

    ​, 将該元素添加

4.HashSet 實際是 HashMap 中的 ​

​key​

​ 部分

5.HashSet 和 HashMap ​

​初始化容量都是16​

​,​

​預設加載因子是0.75​

加載因子: 它是指哈希表在自動擴容之前可以達到多滿的一種度量。當哈希表中的數量超過了加載因子和目前容量的乘積,則哈希表自動擴容,也就是​

​rehash​

​。

擴容的操作實際是建立了一個是原容量的兩倍的哈希表,并将原來對象放入新的哈希表中。

import java.util.*;
public class SetTest01 {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub

    //建立一個set集合
    Set s = new HashSet();
    
      //添加元素:無序不可重複
    s.add(1);
    s.add(20);
    s.add(20);
    s.add(100);
    s.add(99);
    
    //周遊
    Iterator it = s.iterator();
    while(it.hasNext()){
      System.out.print(it.next()+" "); // 1 100 99 20 
    }
  }
}      
【Java】集合.Set接口

案例:假設進行學生姓名、學号的添加

import java.util.*;
//根據現實要求,學生的編号為:1000-9999
class Students{
  
  //姓名
  String name;
  
  //編号
  String no;
  
  //構造方法
  Students(String name,String no){
    this.name = name;
    this.no = no;
  }
  
  //重寫equals方法,隻有當hashCode方法傳回的相同時,才會調用equals方法進行比較
  public boolean equals(Object o){
    if(this==o){
      return true;
    }
    if(o instanceof Students){
      Students s = (Students) o;
      if(s.name.equals(name) && s.no.equals(no)){
        return true;
      }
    }
    return false;
  }
  
  //重寫hashCode方法
  public int hashCode(){
    return no.hashCode();
  }
}

public class SetTest02 {
  /**
   * @param args
   */
  public static void main(String[]) {
    // TODO Auto-generated method stub

    //建立一個Set集合
    Set s = new HashSet();
    
    Students s1 = new Students("張三","10000");
    Students s2 = new Students("張三","10000");
    Students s3 = new Students("王五","20000");
    Students s4 = new Students("趙六","20001");
    Students s5 = new Students("孫七","30000");
    Students s6 = new Students("錢八","30001");
    
    //添加元素
    s.add(s1);
    s.add(s2);
    s.add(s3);
    s.add(s4);
    s.add(s5);
    s.add(s6);
    
    //檢視結合元素
    System.out.println(s.size()); // 5
  }
}      

​​傳回頂部​​

二、Set接口:SortedSet、TreeSet

1.SortedSet 特點:無序不可重複,但是存進去的元素可以按照元素大小自動排序。

2.SortedSet集合排序的方式:

2.1 Comparable接口

被存儲的元素實作了Comparable接口,SUN編寫的集合在添加元素的時候,會調用compareTo方法進行比較。

/**
 *  java.util.Set;
 *     java.util.SortedSet; 
 *        java.util.TreeSet;
 * @author DELL
 *
 */
import java.util.*;
import java.text.*;
public class SortedSet01 {

  /**
   * @param args
   * @throws ParseException 
   */
  public static void main(String[] args) throws ParseException {
    // TODO Auto-generated method stub

    //建立集合
    SortedSet ss = new TreeSet();
    
    //添加元素
    ss.add(13);
    ss.add(11);
    ss.add(9);
    ss.add(9);
    ss.add(20);
    ss.add(35);
    
    //周遊
    Iterator it = ss.iterator();
    while(it.hasNext()){
      System.out.print(it.next()+" "); // 9 11 13 20 35 
    }
    
    //建立集合
    SortedSet strs = new TreeSet();
    
    //添加元素
    strs.add("jack");
    strs.add("sun");
    strs.add("alice");
    strs.add("king");
    
    //周遊
     it = strs.iterator();
    while(it.hasNext()){
      System.out.print(it.next()+" "); // alice jack king sun
    }
    
    //日期
    String t1 = "2016-04-04";
    String t2 = "2020-06-06";
    String t3 = "2015-05-05";
    String t4 = "2012-01-01";
    String t5 = "2000-12-29";
    
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    
    Date d1 = sdf.parse(t1);
    Date d2 = sdf.parse(t2);
    Date d3 = sdf.parse(t3);
    Date d4 = sdf.parse(t4);
    Date d5 = sdf.parse(t5);

    //添加
    SortedSet time  = new TreeSet();
    
    time.add(d1);
    time.add(d2);
    time.add(d3);
    time.add(d4);
    time.add(d5);
    
    //周遊
    System.out.println();
    it = time.iterator();
    while(it.hasNext()){
      Object element = it.next();
      if(element instanceof Date ){
        Date d = (Date) element;
         System.out.println(d);
      }
    }
  }
}      

接下來我們按照以上的内容添加新的對象user

import java.util.*;

class User{
  
  int age;
  
  User(int age){
    this.age = age;
  }
  
  public String toString(){
    return "User[age="+age+"]";
  }
}
public class SortedSet02 {

  /**
   * @param args
   */
  public static void main(String[]) {
    // TODO Auto-generated method stub

    //建立集合
    SortedSet users = new TreeSet();
    
    User u1 = new User(15);
    User u2 = new User(16);
    User u3 = new User(25);
    User u4 = new User(13);
    User u5 = new User(11);
    
    //添加元素
    users.add(u1);
    users.add(u2);
    users.add(u3);
    users.add(u4);
    users.add(u5);
    
    //周遊
    Iterator it = users.iterator();
    while(it.hasNext()){
      System.out.println(it.next());
    }
  }
}      

但是在運作的時候,控制台出現了報錯:​

​ClassCastException: Set接口.User cannot be cast to java.lang.Comparable​

Exception in thread "main" java.lang.ClassCastException: Set接口.User cannot be cast to java.lang.Comparable
  at java.util.TreeMap.put(TreeMap.java:542)
  at java.util.TreeSet.add(TreeSet.java:238)
  at Set接口.SortedSet02.main(SortedSet02.java:36)      

在以上的代碼中user并不是可以比較的對象,之是以之前的三個例子(Integee、String、Date)可以比較,是因為都繼承了Comparable 接口,可以調用compareTo(T o) 方法進行比較。

【Java】集合.Set接口
【Java】集合.Set接口
【Java】集合.Set接口

在程式進行運作時,java内部進行了類似如下指令:

Comparable c = (Comparable) user ;
//面向接口調用
c.compareTo();      

而此時我們的​

​User​

​類并未實作​

​Comparable接口​

​。

在源碼中我們可以看到,​

​TreeSet​

​底層是​

​TreeMap​

​:

【Java】集合.Set接口

在​

​TreeSet​

​中的add方法調用的是​

​TreeMap​

​中的​

​put​

​方法:

【Java】集合.Set接口

在​

​put​

​方法中強制将​

​key​

​轉化,這裡的​

​key​

​等同于​

​user​

​對象,而​

​User​

​類并未實作​

​Comparable​

​接口,是以報錯。

【Java】集合.Set接口

同時在put方法中運用到了​​二叉樹(此處查找了一些資料,感謝該作者提供的文章。)​​

【Java】集合.Set接口

對​

​User​

​類進行修改後:

class User implements Comparable{
  
  int age;
  
  User(int age){
    this.age = age;
  }
  
  public String toString(){
    return "User[age="+age+"]";
  }

  @Override
  /*實作java.lang.Comparable;接口中的comparaTo方法
   * 該方法有程式員來進行實作,sun公司的程式負責了調用該方法
    需求:根據User的年齡排序
  */
  public int compareTo(Object o) {
    int age1 = this.age;
    int age2 = ((User) o).age;
    return age1-age2;
  }
  
}      
return age1-age2;      
【Java】集合.Set接口
return age2-age1;      
【Java】集合.Set接口

​​傳回頂部​​

2.2 單獨編寫一個比較器

【Java】集合.Set接口

在​

​TreeSet​

​中有這樣一個方法可以傳回一個比較器。在建立​

​TreeSet​

​集合時提供一個比較器,傳入元素時經過比較器比較。

import java.util.*;
class Product{
  
  double price;
  
  Product(double price){
    this.price = price;
  }
  
  public String toString(){
    return price+"";
  }
}
//單獨寫一個比較器
class ProductComparator implements Comparator{

  @Override
  //需求:按照商品價格排序
  public int compare(Object o1, Object o2) {
    
    double price1 = ((Product) o1).price;
    double price2 = ((Product) o2).price;
    if(price1==price2){
      return 0;
    }else if(price1>price2){
      return -1;
    }else{
      return 1;
    }      
  }

}

public class SortedSet03 {

  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub

    //建立集合時提供一個比較器
        SortedSet product = new TreeSet(new ProductComparator());
        
        Product p1 = new Product(7.0);
        Product p2 = new Product(15.0);
        Product p3 = new Product(3.0);
        Product p4 = new Product(4.5);
        Product p5 = new Product(7.6);
        
        //添加
        product.add(p1);
        product.add(p2);
        product.add(p3);
        product.add(p4);
        product.add(p5);
        
        //周遊
        Iterator it = product.iterator();
        while(it.hasNext()){
          System.out.println(it.next());
        }          
  }
}      
【Java】集合.Set接口

2.3 匿名内部類(不推薦,隻能使用一次)

  • 不常用,這裡不做介紹~