blog 2019.3.19 && 3.20 Day19&&Day20 集合框架

在这里插入图片描述
在这里插入图片描述
多态
小插曲:数组是如何实现乾坤袋功能的?
装父类类型的数组 添加的时候添加子类类型的数组

集合框架

基本概念

集合出现是为了解决数组在开发过程中所遇到的问题
特点:
1、长度不是固定的,可以随时扩容
2、可以存放不同类型的数据
3、提供了很多种集合,不同的算法。采用合适的集合框架可以提高开发效率。

在这里插入图片描述
左半边 集合框架 右边 Map框架(不输入collection集合框架)
虚线:接口
实线:类

collection 集合框架顶层接口 提供了集合框架的基本特征
collections sun公司提供给我们操作集合的各种方法,工具包

简化版:(背)
在这里插入图片描述

1、 研究左边的list
2 、研究右边的set
3 、研究map

集合的结构

Collection

Collection是一个接口,不提供直接的实现,List、set这两个子接口都是继承于Collection,代表的是一种规则,它所包含的元素必须遵循一条或多条规则,比如:有些允许数据重复,有些不允许数据重复,有些数据有顺序,有些又没顺序。

在实际开发中,一般不使用Collection来开发,而是使用它的子接口来进行开发。Collection仅仅提供的是一种规范。

List接口

List接口,是Collection的直接子接口,代表的是有序的Collection,Collection里面制定的规范(比如元素必须有序)List就是一个很好的规范实现者。List采用某种特定的插入顺序来保证里面的数据都是有顺序的。用户可以对list中存放的数据根据位置来进行精确的控制,同时可以根据元素的索引来获取到元素的内容。

List的特点 :
1、list中的元素是有顺序的
2、list里面允许元素的重复出现
3、list可以支持null数据
4、可以使用索引来获取list中的元素(类似数组)。

ArrayList

ArrayList是一个动态数组,是最常用,常见的集合,允许任何符合规则的元素插入,甚至包括也可以插入。ArrayList底层是数组,但是这个数组可以进行动态扩容,底层默认初始化的容量为10,该容量代表数组的大小。随着集合中元素的内容不断增加,容器的大小也会随着变化,每次向容器中加入数据的死或坏都要去检测当前容量是否够使用,当快要溢出的时候,进行扩容。但是扩容的效率比较低。

扩容:创建一个新的数组,将以前的数据赋值到新的数组,再将以前的数组废弃。

增:

创建数组并赋值

第一步:
在这里插入图片描述
第二步:
在这里插入图片描述
可以把2加进去,2是基本类型而且不是object类型,为什么?
说明这里有个自动装箱功能,把2变成Intger装进去了。
在这里插入图片描述
在这里插入图片描述
既可以装数字,又可以装字符串,小数,

完了。

查:

获取数组数据
get指定输出,foreach输出所有
取一个:
在这里插入图片描述

全部取:
在这里插入图片描述
因为里面既有int 又有float 还有字符串,这里直接输入一个object解决一切。

完了。

查询集合中是否有学生的对象(用于匹配当前对象在不在这个集合,在就不加)
在这里插入图片描述

删:

删除集合中的数据:
在这里插入图片描述
括号里不能直接删除某个 “ 值”
只能删除对象,根据对象的地址来删

修改集合框架中的数据
在这里插入图片描述
第一个 1 是数组中对应位置的下标

.length 求数组的长度
.length() 求字符串的长度

LinkedList

ArrayList和LinkedList都是实现了List接口,ArrayList是一个动态数组,底层是一个双向链表,LinkedList除了有AarrayList的一些方法以外,提供额外的一些方法,通过一些方法操作链表的头和尾。
由于两种集合底层数据结构不同,Linkedlist不能随机访问,所有的操作都是按照双向列表来执行的,在列表中索引会采用从头到或者结尾来遍历数据,这样做的目的是在操作集合的时候删除,增加可以提高效率。

双向列表:
列表中每个元素都是独立的,每个空间都存放本身的数据,以及上一个对象的引用和下一个对象的引用(索引)。

用法:

在这里插入图片描述


删除

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

Vector

与ArrayList很相似,底层都是动态数组,但是Vector是线程同步的,在操作数据的方法上面加上了synchronized关键字,它的线程安全的。jdk 1.0就开发出来了Vector,jdk1.2后才开始提出集合框架。有很多程序还是用Vector来完成的,java为了向后兼容,就将vector放在了list下面,保留了以前vector的特性,但是现在一般都有ArrayList。

效率比ArrayList低。

说一下三种集合框架各自的优点

1、ArrayList的底层是一个动态数组,而LinkedList底层是==双向链表(是啥?下面有解释)==来实现的。
2、对于随机访问数据,get/set,ArrayList的效率比LinkedList的效率高,因为ArrayList底层是一个动态数组,查找元素在一个连续的空间找,速度飞快。LinkedList要移动我们的指针(索引),去判断当前元素下一个元素是否是我们需要的(因为linkedlist里面存储的数据是东一个西一个,并不连续)。
3、ArrayList结构对数据进行增删的时候效率比较低,中间插入一个元素,以后的所有元素都得挪动位置,下标都得变化。LinkedList前一个元素只需要改变引用,后一个需要改变引用
4、Vector线程安全,效率非常低。
5、ArrayList扩容的效率比较低,若你提前能确定空间大小,则优先使用构造器来初始化容量。

《ArrayList》源码解析:
当你调用add方法的时候,检查数组是否够用,如果不够用,将创建一个容量大一倍的数组,将原来数组的数据拷贝到新数组中,将原来的数组废弃。

当你调用remove方法的时候,将指定元素移除数组后,将后面的元素整体向前移动,
通过System.copyof()来实现,一次删除会有多个元素进行移动,同样,add添加的时候,添加到指定位置也会整体移动。

《LinkedList》源码解析:
LinkedList是基于链表的数据结构 每个元素都包含了 上一个和下一个元素的引用,所以add/remove 只会影响到上一个和下一个元素。

链表结构:
单链表:单链表中链表对象维护了一个first引用,该引用指向节点链表中的第一个节点元素,每个节点对象维护了一个next引用,next指向了下一个元素引用。(节点对象Node:当前这个对象有自己的数据和下一个元素的引用)
单链表

双向链表:链表对象维护了一个first引用和last引用,这两个引用分别指向链表的首和尾,每个节点对象维护了对象的数据,prev(上一个引用)、next(下一个引用),用来指向节点前后对象。
双向链表
在双向链表里,后面只能找到前面的引用(next),前面(prev)的能找到后面的数据(data)

3-20号接着昨天的内容

泛型

在这里插入图片描述

在储存对象时候,由于底层是object接口可以存任何类型的数据, 字符 数字 都可以
所以在用下标取的时候,如果要将当前对象转化为要使用的对象必须知道取出来的值是什么类型的,不然经常会出现java.lang.ClassCastException;(例如上图,下标为0的对应为数字1,但是要强转为String类就是错的,虽然编译不出错,但是运行不来)。


这个时候就引入了泛型。
在这里插入图片描述
这里的 < >里面就规定了要传的类型。

在这里插入图片描述

取数据
在这里插入图片描述
这时返回的是userBean 而不是object
在这里插入图片描述
这时就不用考虑数据转换的时候出现错误了,因为上面已经规范了输入的标准。


泛型能带来什么好处?

E : Element
T : Type
K : Key
V : Value
泛型在定义接口的时候指定了参数类型。这个参数类型默认是用E(代表element)来表示元素,类型参数值是在申明变量或者创建对象的时候确定。泛型就是创建一个同类型的数组

如果给集合制定泛型,那就意味着操作内容就必须传递制定的参数类型。在获取集合中的数据的时候,可以不用再转化对象类型,默认就返回传递的泛型类型。

E表示一个占位符。

问题:
一旦确定了参数类型,泛型就确定了。传递参数的时候必须是跟泛型同样的数据。
场景: 公司里面有员工、领导,我们要在不同情况下表示不同泛型,怎么办?

List<User> list = new ArrayList<User>{};

一旦确定,只能存User了。
这时候 用问号

  List<?> list ;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以设置泛型的占位符为问号,等你具体传过来的时候再确定的啥对象。在运行的时候再确定具体的内容。根据子类的泛型来决定父类的泛型。
在这里插入图片描述

set接口

在这里插入图片描述


在这里插入图片描述
list是通过下标一个一个取,在空间中是连续的 set是在内部自己排列。不一定是按顺序排列的。


在这里插入图片描述
清空所有。


在这里插入图片描述
判断当前接口内是否有某元素


在这里插入图片描述
判断是否为空


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

虽然内容一样,但是地址不一样,所以可以都输出。怎么办?如何识别两个是一样的?
–》去userBean去重写hascode和equals

咋重写?

在hashset集合中存放对象,只要调用add方法需要进行比较,调用对象hashcode方法和equals方法比较对象是否一样,如果一样不会放进去。

判断两个对象是否相等的过程:
1、set(hashset)会判断两个对象的hashcode码是否一样(hashcode一旦确定,元素在内存中的位置也将确定下来,桶运算。),如果说两个对象的hashcode码不一样,这两个对象就不相等。
2、如果hashcode码相等的话,再调用对象的equals方法来比较值是否相等。如果值相等,才确定这两个对象相等。

深入挖掘:
hashSet数据结构:采用了hash表(看到hashset 、hashcode 、hashmap肯定用到了hash表 hash表就是一系列对象)
jdk1.8之前: hash表= 数组+链表
jdk1.8及之后:hash表=数组+链表
数组+红黑树(红黑树的特点:查询效率非常快)
jdk1.8中,hash存储采用数组+链表+红黑树来存数据,当产生hash冲突的时候(hash值一样,但是内容却不一样)值就会用链表来村,但是链表长度超过8的时候,自动变成红黑树来进行排序。

hashmap把一堆键 放一起就成了hashset


String类直接就重写了hashcode 所以只会出现一个abc
在这里插入图片描述


哈希冲突

java中用哈希算法的时候会出现问题,两个值不一样但是hashcode码相同
在这里插入图片描述

重地和通话。的hashcode码 一样的
在这里插入图片描述
存放的时候就是这种链表关系,一个地址存两个值。


TreeSet

在这里插入图片描述
1、可以允许排序的一种集合,继承了SortedSet接口
2、元素也是不能重复
3、底层是基于treemap来实现的(hashset是基于hashmap来实现的),基于红黑树算法。TreeSet的数据来源于Treemap的key值,采用自然排序或用户自定义排序

了解红黑树。

在这里插入图片描述
《因为重写了排序算法,所以输出的元素是按照顺序排列的。
元素(对象)如果放到了treeset中,他不知道怎么排序,所以必须在对象里面实现了一个comparable 接口(输入object),重写compareTo。
如果加入的是1 2 3这种值,treeset可以进行自然排序。》

老师的笔记:
特点:在存储数据的时候,存放的数据是数值或者字符串(本身有排序算法),按照默认排序(自然排序。)
存放的数据是对象的时候,treeset默认是不知道你的对象怎么比较,需要存放的对象身上实现Comparable,重写ComparaTo方法来实现自定义的排序。

Comparable称为比较器,常用于集合框架里面。

hashmap的就是hashset
treemap的就是treeset

treeset也具有去重的功能,自己默认重写了hashcode和equals判断是否去重,并通过这个进行排序输出。

hashset treeset以后不管存数据的时候,不管是什么数据,都要进行去重


重写compareTo
在这里插入图片描述
在这里插入图片描述


迭代器(iterator接口)

迭代器就是用于遍历集合的一种接口。
遍历就是从集合中取出每一个元素的过程,在collection中有一个iterator对象,通过这个对象可以遍历集合中所有的元素。

说白了,迭代器就是提供给集合用,用于输出数据 (foreach的功能)。

迭代器的用法

在这里插入图片描述

若想一次性获取所有数据,则需要循环。
在这里插入图片描述
先判断迭代器里面有没有数据。
在这里插入图片描述

所有的集合类都可以使用迭代器来完成数据的获取。
通过调用iterator获取到迭代器的接口对象,返回迭代器泛型,值根据集合的泛型来定的。
next方法可以获取到集合中的元素。

迭代器的使用。
在这里插入图片描述

通过使用collections方法包的方法 倒叙输出
在这里插入图片描述
顺序排列
在这里插入图片描述

区分Collections 和Collection

Collections:集合工具包,用于操作collection所定义的各种集合。所有方法都是静态的,可以直接调用。比如排序 反转 对元素进行搜索 线程安全内容。
Collection:接口,集合的顶层框架,主要用于制定集合的规范。

HashSet和TreeSet的区别

Set集合中的元素是无序的,不可重复的。这个接口下有两个常用集合的实现,HashSet和TreeSet。

HashSet

HashSet底层用的是哈希表,它把对象根据其哈希值存放到对应的区域里。由于这种特性,两个在不同区域的对象会被认为不相同的。
所以如果对象要存放到Hash集合里面,则需要重写对象的hashCode方法,让相等的对象的hashCode的值也相等。

TreeSet

TreeSet采用的数据结构是红黑树,我们可以让它按指定规则对其中的元素进行排序。它又是如何判断两个元素是否相同呢?除了用equals方法检查两个元素是否相同外,还要检查compareTo方法是否返回为0。
所以如果对象要存放到Tree集合里,需要在重写compareTo时,把相同的对象的比较值定为0,防止相同的元素被重复添加进集合中。


1、HashSet与TreeSet接口的一点不同,HashSet 保存的数据是无序的,TreeSet保存的数据是有序的,所以如果要想保存的数据有序应该使用TreeSet子类。

2、利用TreeSet保存自定义类对象的时候,自定义所在的类一定要实现Comparable接口,如果没有实现这个接口那么就无法区分大小关系,而且在TreeSet中如果要进行排序,那么就要将所有的字段都进行比较,就是说在TreeSet中是依靠comparato()方法返回的是不是0来判断是不是重复元素的。

3、如果是HashSet子类,那么其判断重复数据的方式不是依靠的comparable接口而是Object类之中的两个方法:(1)取得对象的哈希码 hashCode();(2)对象比较:equals(); 这俩个方法均不需要自己编写,在eclipse里面可以使用右键source 选择自动生成。就像生成Getter 和Setter 方法一样。

总结:TreeSet 依靠的是Comparable 来区分重复数据;
HashSet 依靠的是hashCode()、equals()来区分重复数据
Set 里面不允许保存重复数据。


猜你喜欢

转载自blog.csdn.net/qq_39263750/article/details/88667351