java arraylist排序_Java-08-Collection 简介

Java 中的 Collection 接口是 Java Collection 体系的根接口。

c255c4979aeb2e0e55bb0187b0035cfc.png
https://www.ict.social/java/collections-and-streams-in-java/java-collections-framework

因为 Java 有接口,所以它先定义了一个 Collection 接口,进行了一个抽象,关于 Collection 的解释,源码中的注释部分是讲得最好的:

634953d991974c243d69248568bbeeb1.png
是 collection 继承体系的根接口,代表一组对象,被称为“元素”。一些 集合(collection)允许重复元素,还有一些一盒不允许。一些是有序的,还有一些是无序的...

根据图片,我们可以看到,有几个比较重要的分支,分别具有不同的特性:

  1. List
  2. Set
  3. Map

它们也都是接口,描述了这一类型的 Collection 应该有的方法,下面我会介绍这几个类型比较重要的实现类。

ArrayList

有序、可重复的集合。

本质上就是一个数组,但是是一个可自动扩容的数组。我们看 ArrayList 的源码的话,就会发现,实际上是在每次存储的时候,ArrayList 内部都会判断当前数组的长度是否够大,如果不够,则会创建一个更大的数组,并把当前的值拷贝进去。

oldCapacity >> 1 这个我们在位运算中遇到过,左移一位的话,就是相当于除以当前的进制,所以这里可以看到,ArrayLIst 每次扩容的大小是当前大小的 1.5 倍。

c99f9c91553a7d6b3709663da4970db6.png

List 的其他实现类

  • TreeList 支持排序的 List。比如按对象的年龄属性从小到大,按字符串的长度等等。
  • LinkedList 链表,适合插入和删除操作比较频繁的 List。

HashSet

无序,不可重复的集合。

不可重复的意思是不能包含相同元素,那如何判断元素是否相同呢?使用 equals 方法来判断。

我们先假设我们自己要实现一个不可重复的集合,我们会怎么做呢?

好像也不难。

05acbdd7c3df2676cac8bbe3d18c3c80.png

如果当前集合中包含的一个元素,等于即将添加的元素,那我们就什么都不做,反之就添加,似乎就实现了。但是这个实现存在非常严重的效率问题,即当你的数据越来越多,你每添加一个元素,就要遍历一遍现有的元素。

我们使用 Set 来做一个测试:

3502ac9dd9bac248ef16cd14567f4cd6.png

判断当前集合是否包含一个元素,ArrayList 用了 7.8毫秒,而 HashSet 只用了 0.04毫秒,可以想象这个效率的差距是多么巨大。

那 HashSet 是怎么做到的呢?这个就和它名字中的 Hash 有关了。

假如我们现在有 1000 个人,然后新来了一个人,我们要判断新来的人的名字是否在 1000 个人里面已经存在了。

ArrayList 的做法是:让 1000 个人按顺序排好,然后挨个找,如果找到了同名的,就结束。

HashSet 的做法是:让 1000 个人按照姓氏分组,姓张的一组,姓王的一组...这样把 1000 个人分成了很多组,当新来一个人的时候,直接在对应的组里去找,如果找不到,就找不到了。或者根本连对应的组都找不到。

看出来了吗?ArrayList 永远是在所有数据里找,而 HashSet 是在一小部分数据里找,所以 HashSet 当然要快很多。

人可以根据姓氏分组,那 String,Integer,以及其他的 Object,又应该如何分组呢?

hashCode

hashCode 和 equals 通常会被同时重写,关于 hashCode 有这几个约定:

  1. 同一个对象必须始终返回相同的 hashCode
  2. 两个对象的 equals 返回 true,必须返回相同的 hashCode
  3. 两个对象不同,也可能返回相同的 hashCode

要特别注意的是:hashCode 方法返回的是 int,我们都知道 int 的取值范围是有限的,所以极有可能两个完全不同的对象,但是返回相同的 hashCode,但是 hashCode 相同并不代表 equals 相同,也不代表两个对象相同,判断对象相同的方法只有 equals。

所以我们每个对象都有自己的“姓氏”了,也就方便了一些 Hash 结构。

Set 的其他实现类

  • TreeSet 支持排序的 Set。比如按对象的年龄属性从小到大,按字符串的长度等等。
  • LinkedHashSet 元素按照插入顺序排列的 Set。

HashMap

无序,Key 不可重复,Value 可重复的集合,存储的是 Key-Value 键值对。

首先名字里面的 Hash 我们已经理解了,就是为了实现 Key 不重复,借助 Hash,可以快速判断出是否存在重复的 Key。诶,等等,那 HashMap 的 Key 不就是一个 HashSet 吗?

我们打开 HashSet 的源码:

3bb815ec23bf996537de29868977e357.png

原来 HashSet 中真的包含了一个 HashMap,因为 HashSet 能做的事情,HashMap 应该都能做,而 HashMap 又多出了 Key-Value 的映射功能,所以这里「组合」了 HashMap 的实现。

HashMap 的其他实现类

  • LinkedHashMap 根据上面所提到的,Linked 就代表元素的顺序是根据插入顺序的。
  • TreeMap 根据上面所提到的,Tree 就代表可以支持自定义排序的。

不常用的实现

  • Queue 队列(先进先出)
  • Deque 和 Quue 类似,但是是一个双端队列,支持获取第一个元素,以及最后一个元素
  • PriorityQueue 优先级队列,和普通的队列区别是支持排序

总结

一个实现类,往往代表了一种数据结构,我们应该使用特定的数据结构来解决特定的问题,如果发现 JDK 自带的实现类满足不了我们特定的问题,可以考虑使用优秀的第三方库,如 Guava。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值