一、集合概述
一、集合框架的概述
1.集合、数组都是对多个数据进行存储操作的结构,简称java容器。
说明:这里说的存储,主要是内存层面的存储,不涉及持久化的存储。
2.1数组在存储方面的特点(两者相比较)
一旦初始化以后,其长度就确定了。言外之意 这是一个缺点
数组一旦定义好之后,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。例如:String[] arr ;int [] arr;等等。
2.2数组在存储方面的缺点:
初始化之后,长度确定了,不可以修改了。
数组中提供的方法比较少,对与删除插入数据等操作,非常不便,效率不高。
获取数组中实际元素的个数的需求,数组中没有现成的属性或方法可以使用
数组存储数据有序、可重复。对与无序、不重复的需求,数组是不能满足的。
二、java的集合体系、集合框架:
collection接口 实线代表继承,虚线代表实现类
map的体系
Collection接口:单列集合接口,用来存储一个一个的对象
List接口:有序的可重复的数据。习惯上吧List称作动态数组。
ArrayList/LinkedList/Vector
Set接口:无序的不可重复的数据
HashSet/LinkedHashSet/TreeSet
Map接口:双列接口 k-v的存储形式。
HashMap/LinkedHashMap/TreeMap/HashTable/Properties
二、Collection
Collection接口中的常见方法:
Iterator:集合元素遍历接口 迭代器
Iterator对象成为迭代器(设计模式中的 一种),主要用于遍历Collection集合中的元素。
迭代器模式定义为:提供一种方法访问容器Collection对象中各个元素,而又不暴露该对象内部细节。迭代器模式就是为容器而生。
用法:
foreach:for循环的增强,用于遍历集合数组。
foreach内部原理仍是调用的迭代器
List
比较ArrayList/LinkedList/Vector三者之间的异同:
同:三个类都实现了List接口,存储数据特点相同:存储有序的,可重复的数据
不同:ArrayList作为List的主要实现类,执行效率比较高,效率不安全。底层依旧使用Object[]存储。
LinkedList:底层使用双向链表,对与频繁的插入删除操作,使用此类效率较高。
Vector作为List的古老实现类,jdk1.0就出现了,作为List接口出现之前的实现有序可重复存储的方法。线程安全的效率低syn。底层使用Object[]存储。
ArrayList
源码分析:jdk7和jdk8有差距
jdk7:
ArrayList list=new ArrayList();//底层创建了长度是10的Object[]数组 elementData
list.add(123);// elementData[0]=new Integer(123);
....
list.add(11);//如果此次的添加导致底层的elementData数组容量不够,则扩容。
默认情况下扩容为原来容量的1.5倍,同时将原有数组中的数据拷贝到新的数组中。
结论:建议在开发中使用带参构造器:ArrayList list=new ArrayList(int capacity);//直接定义好数组长度,从而尽可能的避免扩容。
jdk8:
ArrayList list=new ArrayList();//底层Object[] elementData初始化为{}.并没有帮我们去创建长度为10的数组。
list.add(123);//第一次创建了长度为10的数组,并将数据添加到elementData
....
后续的添加和扩容操作 与jdk7没有区别
jdk7与jdk8的总结:
7是类似于饿汉式创建对象,8是类似于懒汉式创建,延迟了数组的创建,节省内存。
LinkedList
源码分析:
LinkedList list =new LinkedList()//内部声明了Node类型的first和last属性,默认值为null。
list.add(123) //将123封装到Node中,创建了Node对象。
其中Node定义为:
可以确定 Node确实是双向链表
Vector(忽略了)
扩容方式有不同:默认为2倍。
Set
Collection接口:单列集合接口,用来存储一个一个的对象
Set接口:无序的不可重复的数据
HashSet:作为Set接口的主要实现类,线程不安全。
LinkedHashSet:是HsahSet的子类。遍历内部数据时,是按照添加顺序来的(不是有序)。
TreeSet:使用红黑树存的,可以按照添加对象的属性,进行排序。
理解Set的无序性和不可重复性:
无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值判断
不可重复性:保证添加的元素按照equals()判断时,不能返回true.相同元素只能添加一个。
添加元素的过程:以HashSet为例:
添加第一个数据,由于里面没有数据,那么直接添加即可,
添加第二个需要调用equals方法进行比较,返回false,才能进行添加,
添加第三个数据需要和前两个数据依次比较。
....
添加第1000个数据,就需要和前999个数据都进行比较。
这样来说,效率就会很低。
Set用了一种巧妙地方式进行实现,
我们向HashSet中添加a
首先调用元素a所在类的HashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中存放的位置(索引位置)是否已经有元素,
如果此位置上没有元素,则直接添加成功。
如果此位置上已经有元素b或以链表形式存在其他元素,则比较元素a与b的哈希值
如果哈希值不相同,则添加a成功
如果相同
调用元素a的equals()方法
方法返回true 添加失败
方法返回false 添加成功
对与添加成功这样的情况:a和制定索引位置上数据以链表形式存储
jdk7:元素a存放到数组中,指向原来的元素
jdk8:原来的元素指向a
注意:
1、Set接口没有额外定义新的方法,使用的都是Collection中声明的方法。
2、要求:向set中添加的数据,其所在的类一定要重写hashCode()和equals()
重写的hashCode()和equals()尽可能保持一致性:相等对象必须具有相等的散列码。
HashSet
LinkedHashSet
LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此前数据前一个数据和后一个数据。
优点:对与比较频繁的便利操作要优于HashSet
TreeSet
可以按照添加对象的指定属性,进行排序。
1、向TreeSet中添加的数据,要求是相同的类的对象。
2、两种排序方式:
自然排序实现CompareTo接口,和定制排序实现Comparator
三、Map
除了SortedMap都是他的实现类
Map:双列结构,存储k-v对的数据
HashMap:主要实现类
LinkedHashMap:
TreeMap:
Hashtable:古老实现类
Properties:
hashmap和hashtable的区别:https://blog.csdn.net/wangxing233/article/details/79452946
hashmap源码分析:https://blog.csdn.net/qq_43925089/article/details/107134607