Java-集合

Java-集合

1 概念

Java集合是使程序能够存储和操作元素不固定的一组数据,所有Java集合类都位于java.util包中

数组和集合对比:

数组集合
长度固定长度不固定
存放任意类型不能存放基本数据类型,只能存放对象的引用

注意: 如果集合中存放基本数据类型,一定要将其"装箱"成对应的"基本数据类型包装类".

2 继承体系

Java中的集合类主要由连个接口派生而出:Collection和Map.Collection和Map是Java结合框架的根接口,这两个接口又包含了一些子接口和实现类

image-20210628191300826

image-20210628191316787

由以上两图我们可以看出Java集合类有清晰的继承关系,有很多子接口和实现类。但是,并不是所有子接口或实现类都是最常用的。

下面我们列举出最常用的几个子接口和实现类:

Collection ——> List ——> ArrayList类

Collection ——> List ——> LinkedList类

Collection ——> Set ——> HashSet类

Collection ——> Set ——> SortedSet接口 ——> TreeSet类

Map ——> HashMap类

Map ——> SortedMap ——> TreeMap类

3 Collection

Collection接口是List接口和Set接口的父接口,它定义的方法可以用于操作List集合和Set集合。

Collection接口定义的方法:

image-20210628191728353

image-20210628191748114

image-20210628191806882

image-20210628191821062

4 Iterator(迭代器)

迭代器是一种模式,又称光标,它可以使对于序列类型的数据结构的遍历行为和被遍历的对象分离

我们不需要关心该序列底层数据结构是什么样子的,只要拿到这个对象,使用迭代器就可以进行遍历这集合对象

4.1 迭代器生成

Iterator it = 集合对象.iterator();

4.2 迭代器的三个方法

1 boolean hasnext();判断光标的下一位是否还有元素,有就是true,没有就是false

2 E next();将迭代器的光标向下移动一位,并取出该元素Element

3 remove();删除当前指向的元素

4.3 注意

迭代器一旦创建,就不能进行添加和删除操作,如果添加或者删除了,必须重新生成迭代器

增强for循环:foreach就是为了让iterator循环访问的形式简单,写起来方便,但是也是不能进行添加和删除操作的

使用普通的for和while循环是可以进行添加和删除的,这种遍历还是和数据结构存储相关的

image-20210628193006912

5 注意

使用contains和remove的时候 如果是自定义类型,需要根据需求覆写equals方法

因为这两个方法底层都会去自动调用对象的 equals方法来进行对象的比较

6 List

6.1 特性

有序,可重复

有指定下标,添加顺序和取出顺序一致

ArrayList : 底层是个Object[] 数组,随机查询效率高,随机删除效率低,默认初始化时10,扩大之后是原来的1.5倍,并且是第一次添加数据的时候进行默认长度设置,只new的时候,不添加数据,则长度为0, 等于是 Object[] elementData= {}; 长度为0

LinkedList : 底层是双向链表,随机查询效率低,随机删除效率高

Vector : 已经过时,属于线程安全,而ArrayList是Vector的升级版 , 默认初始化是10,扩大之后是原来的2倍

6.2 ArrayList

image-20210628193245769

6.3 LinkedList

队列:先到先得

栈:先进后出

链表:链表中保存节点,而一个节点有三部分: 1 添加的数据 2 上一个节点 3 下一个节点

链表是没有下标的,只能从头一个一个找,所有查找较慢

由于链表中都是引用指向,所有删除快,比如三个元素分别是1,2,3 要删除2,只需要1的下一个节点=3的引用,3的上一个节点=1的引用

LinkedList是模拟的双向链表,就是1可以找到2,2也可以找到1

添加指定位置/获取指定位置的值:可以传入索引,但是其实不是下标,而是LinkedList封装的方法,帮助我们自动循环去找

​ 本质上还是循环,因为链表是非连续的空间,只能从头开始一个一个找

​ 只不过LinkedList模拟了下标访问的方式,对我们使用起来提供了便利

image-20210628194023534

image-20210628194040286

6.4 底层实现

6.4.1 节点类

image-20210628194202304

6.4.2 添加

image-20210628194228531

6.4.3 get

image-20210628194259128

7 Set

7.1 概述

无序不可重复

TreeSet : 底层是红黑树(保证元素按照某种顺序排序)

HashSet : 底层是散列

7.2 TreeSet

7.2.1 概述

java.util.SortedSet

​ java.util.TreeSet:会按照某种顺序进行排序

​ 数字:从小到大

​ 字符串:每位的ASCII

​ 日期:自然日期

比较器有两种

​ 要添加的元素实现比较器

​ 专门准备的一个比较器类(优先级高)

进行排序的时候,根据比较器方法返回的值进行比较

​ 如果是0,说明重复,不添加,如果大于0的,说明元素大,往后放

​ 如果是小于0的,说明要添加的元素小,往前放

7.2.2 基本使用

image-20210628195026709

7.2.3 注意

如果要使用treeSet 那么 元素必须有比较器,两种都可以

否则就会有类型转换异常

1 要添加的原始 实现java.lang.Comparable接口,并实现compareTo方法

2 要写一个比较器类,实现java.util.Comparator比较器接口

很多常用的类都实现了Comparable接口并实现compareTo方法

​ 比如:Integer,String,Date等

所以我们自定义类型的时候,一定要弄比较器类

image-20210628195409538

7.3 比较器

可以让集合中的元素按照某个规则进行排序

在源码中体现了,先判断是否有compare() 如果没有再判断是否有compareTo()

image-20210628195444823

所以 Comparator优先级要高于Comparable

7.3.1 Comparable

也可以叫元素自身比较器,就是要添加的元素需要实现这个接口,一般在我们的自定义类中常用

因为这种方式,直接让要添加的元素类实现接口就可以,编码方便,而Comparator需要单独写比较器类

因为它优先级低,我们给出的排序规则,如果不满足调用处,它还可以根据Comparator进行排序扩展

此时当调用处进行排序扩展的时候,此时Comparator和Comparable同时存在,则Comparator优先级高,所以最终排序规则会按照调用处指定的规则进行排序

image-20210628195531789

7.3.2 Comparator

1 该类有排序(比如Integer实现了Comparable,并且是升序),但是排序规则不是我们想要的,这个时候需要使用Comparator来进行调整排序,因为优先级高

2 如果该类没有排序(没有实现Comparable接口),该类也不是我们写的,如果此时需要排序,则需要使用Comparator来完成

image-20210628195610212

7.4 List排序

image-20210628195703352

所以 如果保存我们自定义类型,想要排序,必须有一个比较器类

根据需求决定用哪一种即可

image-20210628195736203

7.5 HashSet

image-20210628195910215

image-20210628195922603

所以 HashSet 其实就是HashMap,只不过在set中,把map的value部分给屏蔽了

只对外提供key的操作

image-20210628200016426

8 Map

8.1 概述

Hash算法 : 是一种安全的加密算法,把不定长的输入变成定长输出,并不能保证其唯一性

同一个对象生成多次hash值,一定是相同的值,不同对象有可能生成相同的hash值

算法 :

直接寻址法、数字分析法、除留余数法、平方取中法

在java中 把散列表封装到了HashMap和HashTable中,并且HashTable已经过时

Hash算法,在java中就是指hashCode方法

8.2 底层实现

map特性 无序 , key不可重复,value可重复 , 保存键值队映射关系,通过key就可以找到对应的value(比如 橘子 买了4斤 )

​ map数据结构,数组中保存链表,链表是个单向链表( 值(Entry对象) , 下一个节点 , hash值)

​ 既然是键值对,那么 这个映射关系由谁来维护呢? Map.Entry

​ 本质 就是 Node<K,V>[];

​ 添加过程 :

​ 先使用要存储的映射关系的key对象调用key对象的hashCode方法,生成hash值,然后通过hash算法进行hash,得到数组下标

​ 判断该下标上是否有元素,没有就创建一个Node对象,把hash,key,value存储,并且next是null,把该Node对象保存到数组对应的下标上

​ 如果该数组位上有节点对象,此时调用当前要添加的映射关系的key的equals方法,和当前数组位上所有 节点对象的key进行比较(比较key的equals和hash)

​ 如果有相等的,就用要添加的键值对的value值替换原来的键值对中的value值,并且key既然重复,不添加

​ 如果没有相等的,就把该键值对封装Node对象,并保存到该数组对应的链表中的尾部,原来的尾部节点对象中的next 保存添加的这个新的Node对象

​ 1.8开始,为了左右平衡,查询效率高,又引入了树

​ 并且在添加中会进行判断,如果数组为中的Node个数 大于等于7 就把该数组位中的所有节点都转换TreeNode,以树状存储

​ HashMap 默认初始化容量是16,并且默认加载因子是0.75

image-20210628200204315

8.3 底层实现

image-20210628200229703

8.4 常用方法

image-20210628200251258

8.5 Map遍历

Map不能直接遍历,需要先转换为集合,然后再使用get方法,获取value

image-20210628200331884

8.6 Properties

image-20210628200422008

9 Map转List并以value排序

1 map 存储键值对而list存储单个元素,第一个问题 就得先把键值对转换为一个单一元素对象(Entry)

通过map.entrySet() 得到set

2 把多个entry封装到list中

ArrayList的构造方法把set传入,或者调用add

3 对list中元素进行排序

Comparator

image-20210628200509825

10 泛型

10.1 概述

类型检查,编译过程中检查类型是否匹配

泛型是在编译阶段对数据的类型进行匹配

优点:统一了数据类型,减少强制类型转换

缺点:只能存储单一类型的数据

结合我们的需求情况,大部分情况都需要保存单一数据类型的数据,所以大部分情况下使用泛型要好很多

泛型只能是引用类型,不能是基本类型

10.2 基本使用

image-20210629170445376

image-20210629170519832

10.3 自定义泛型

泛型本质就是一个占位符,由调用出对这个占位符赋值

如果不赋值默认是Object

常见的占位符:

?表示不确定的类型
T表示一个具体的Java类型Type
K表示key,Java中的键值对
V表示value
E表示Element元素,集合中的数据我们叫元素

用什么字母都是可以的,一般是大写,只是占位符而已

语法:public class Linked

image-20210629171029594

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值