文章目錄
- 集合.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
}
}
}

案例:假設進行學生姓名、學号的添加
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内部進行了類似如下指令:
Comparable c = (Comparable) user ;
//面向接口調用
c.compareTo();
而此時我們的
User
類并未實作
Comparable接口
。
在源碼中我們可以看到,
TreeSet
底層是
TreeMap
:
在
TreeSet
中的add方法調用的是
TreeMap
中的
put
方法:
在
put
方法中強制将
key
轉化,這裡的
key
等同于
user
對象,而
User
類并未實作
Comparable
接口,是以報錯。
同時在put方法中運用到了二叉樹(此處查找了一些資料,感謝該作者提供的文章。)
對
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;
return age2-age1;
傳回頂部
2.2 單獨編寫一個比較器
在
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());
}
}
}
2.3 匿名内部類(不推薦,隻能使用一次)
- 不常用,這裡不做介紹~