hashset treeset java_Java Set集合(HashSet、TreeSet)

什么是HashSet?操作过程是怎么样的?

1、HashSet底层实际上是一个HashMap,HashMap底层采用了哈希表数据结构

2、哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素是一个单向链表,每个单向链表都有一个独一无二的hash值,代表数组的下标。在某个单向链表中的每一个节点上的hash值是相同的。hash值实际上是key调用hashCode方法,再通过"hash function"转换成的值

3、如何向哈希表中添加元素?

先调用被存储的key的hashCode方法,经过某个算法得出hash值,如果在这个哈希表中不存在这个hash值,则直接加入元素。如果该hash值已经存在,继续                调用Key之间的equals方法,如果equals方法返回false,则将该元素添加。如果equals方法返回true,则放弃添加该元素

HashMap和HashSet初始化容量是16,默认加载因子是0.75

HashSet的数据结构

献上我看视频截的图

b9dfdc889f9428e0e53e8749c4408e3b.png

代码举例

1 public classTest{2

3 public static voidmain(String[] args) {4

5 Set set = newHashSet();6

7 Student stu1 = new Student("1", "JACK");8 Student stu2 = new Student("2", "TOM");9 Student stu3 = new Student("3", "JIM");10

11 set.add(stu1);12 set.add(stu2);13 set.add(stu3);14

15 System.out.println("size :" +set.size());16 }17

18

19

20 }21

22 classStudent{23 String no;24 String name;25

26 Student(String no, String name){27 this.no =no;28 this.name =name;29 }30 }

这个的输出结果显而易见是3,因为我们添加了三个元素,但是如果改一下

1 Student stu1 = new Student("1", "JACK");2 Student stu2 = new Student("1", "JACK");3 Student stu3 = new Student("3", "JIM");4

5 System.out.println(stu1.hashCode());6 System.out.println(stu2.hashCode());

可以运行试一下,stu1和stu2的hashCode是不一样的,为什么呢?因为这两个对象是New出来的,引用地址不一样。我们不希望出现这样的情况,那就要重写hashCode和equals方法

1 classStudent{2 String no;3 String name;4

5 Student(String no, String name){6 this.no =no;7 this.name =name;8 }9

10 public booleanequals(Object o){11 if(this == o) return true;12 if(o instanceofStudent){13 Student student =(Student) o;14 if(student.no.equals(this.no) && student.name.equals(this.name)) return true;15 }16

17 return false;18 }19

20 public inthashCode(){21 returnno.hashCode();22 }23 }

再次运行,插入两个数据一样的对象,就不会重复了

TreeSet

treeset实现了sortedset接口,有个很重要的特点是里面的元素都是有序的

1 public classTest{2

3 public static voidmain(String[] args) {4

5 SortedSet set = newTreeSet();6

7 set.add(1);8 set.add(100);9 set.add(50);10

11 System.out.println(set);12 }13

14 }

输出结果:[1, 50, 100]

那如果我们自定义类可以进行比较吗?

1 public classTest{2

3 public static voidmain(String[] args) {4

5 SortedSet set = newTreeSet();6

7 Student stu1 = new Student(22);8 Student stu2 = new Student(11);9 Student stu3 = new Student(100);10

11 set.add(stu1);12 set.add(stu2);13 set.add(stu3);14

15 System.out.println(set);16 }17

18 }19

20 classStudent{21 intage;22

23 Student(intage){24 this.age =age;25 }26 }

这样运行会出现一个问题,报ClassCastException,这就需要来看看源码了,底层到底是怎么实现的,为什么自定义类就先不行呢?

005a6ba4670ee2fc252ba40fa1971e27.png

这里可以看到,当我们在创建一个TreeSet的时候,实际上是new了一个TreeMap

dc37fa76357ca67188af10633cc6890c.png

add的时候调用了TreeMap的put方法,来看看TreeMap中的put方法

a76e3d9ab2673eb0963ec5ea6d04db08.png

可以看到第三个红框那里,会对key进行一个强制类型转换,我们上面的代码肯定是就是在这里装换不成功,Comparable是什么?来看看API

9be69bb6c585f00d3ad27821ee8f16e1.png

是一个接口,从翻译就可以看出,只要实现了这个接口,就是可以比较的,下面是实现了这个接口的类

023999affaeb378b7ae3cb67964084cc.png

随便框了几个,上面就有Integer,这个类实现了comparable接口,因此第一个代码是正确的,现在我们是不是只要实现这个接口就好了呢!

1 class Student implementsComparable{2 intage;3

4 Student(intage){5 this.age =age;6 }7

8 //重写接口中的方法9 //要重写比较规则

10 @Override11 public intcompareTo(Object o) {12 //TODO Auto-generated method stub

13 int age1 = this.age;14 int age2 =((Student)o).age;15 return age2 -age1;16 }17 }

这样OK了,再来看看上面有红框的源码,cmp<0,cmp>0,left,right都是什么东西,二叉树!所以底层是通过二叉树来排序的

如果是自定义类中的String呢,那就return String的compareTo方法就好了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值