文章目录


集合.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接口_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接口_比较器_02


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


【Java】集合.Set接口_返回顶部_04


在程序进行运行时,java内部进行了类似如下命令:

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

而此时我们的User类并未实现​Comparable接口​

在源码中我们可以看到,TreeSet底层是​TreeMap​:

【Java】集合.Set接口_java_05


TreeSet中的add方法调用的是​TreeMap​中的​put​方法:

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


put方法中强制将​key​转化,这里的​key​等同于​user​对象,而​User​类并未实现​Comparable​接口,所以报错。

【Java】集合.Set接口_返回顶部_07


同时在put方法中运用到了二叉树(此处查找了一些资料,感谢该作者提供的文章。)

【Java】集合.Set接口_返回顶部_08


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接口_返回顶部_09

return age2-age1;

【Java】集合.Set接口_java_10


返回顶部


2.2 单独编写一个比较器

【Java】集合.Set接口_哈希算法_11


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接口_set集合_12

返回顶部


2.3 匿名内部类(不推荐,只能使用一次)

  • 不常用,这里不做介绍~

返回顶部