标题:java基础复习—集合
学习内容:
1、集合的总概述
2、Collection接口的代码和底层分析
3、Map接口的常用方法和底层分析
4.Collections工具类的一些方法
5.补充一张图
内容详情:
1、集合的总概述
集合,数组都是对多个数据进行内存层面存储操作的结构,简称Java容器。
为什么用集合不用数组?
数组在存储多个数据方面的缺点:
一旦初始化以后,其长度就不可修改。
数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
Collection接口:单列集合,用来存储一个一个的对象。 又包括 List接口和Set接口
List接口:存储有序的、可重复的数据。(“动态”数组)
包括:
ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
VectorList接口的古老实现类,线程安全的,效率低;底层使用object[] elementData存储
Set接口:存储无序的、不可重复的数据。
HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历
TreeSet:可以按照添加对象的指定属性,进行排序。
Map接口:双列集合,用来存储一对(key - value)一对的数据。**
HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value.
LinkedHashMap: 保证在遍历Map元素时,可以按照添加的颇序实现遍历。 原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高了HashMap .
TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序.
Hashtable:作为古老的实现类,线程安全的,效率低;不能存储null的key和value.
Properties:常用来处理配置文件。key和value都是String类型
2、Collection接口的常用方法和底层分析
2.1.List和Set接口的通用方法
//add,添加数据
//size(),集合大小
//addAll,将另一个集合的元素全部复制过来
//isEmpty,判断集合是否为空
//clear,清空集合的元素
//contains,判断集合是否包含该对象
//containsAll,判断集合是否包含另一个集合的所有元素
//remove,移除集合的某个元素
//removeAll,移除包含另一个集合的所有元素
//equals 判断两个集合是否相等
//retainAll,将本集合和另一个集合相同的元素返回给本集合
//hashCode,返回对象的哈希值
//toArray,将集合转化为数组
2.2.List接口的方法
// void add(int index, object ele):在index位置插入ele元素
// boolean addALL(int index,collection eLes):从index位置开始将eLes中的所有元素添加进来
// object get(int index):获取指定index位置的元紊
// int indexof(0bject obj):返回obj在集合中首次出现的位置
// int lastIndexof(object obj):返回obj在当前集合中末次出现的位置
// 0bject remove(int index):移除指定index位置的元素,并返回此元素
// object set(int index,object ele):设置指定index位置的元素为eLe
// list sublist(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
2.3.ArrayList的源码分析:
jdk 7情况下 ArrayList list = newArrayList();//底层创建了长度是10的object[]数组elementData
list.add( 123);
elementData[e] = new Integer(123);
…
list.add(11);
如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
结论:建议开发中使用带参的构造器:
ArrayList list = new ArrayList(int capacity)//设置大小,避免扩容 jdk 8中ArrayList的变化:
ArrayList list = new ArrayList();//底层Object[]elementData初始化为{}.并没有创建长度
list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData数组
后面的步骤一样
2.4.迭代器
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSew1WW0AnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5YjM5EDMyEjMyADNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
package com.xb.collection;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionIteratorTest {
@Test
//遍历集合
public void test02(){
Collection coll = new ArrayList();
coll.add(133);
coll.add("hahah");
coll.add("无敌");
Iterator iterator = coll.iterator();
while (iterator.hasNext()){//后面还有元素就继续,没有就结束
System.out.println(iterator.next());//指针下移,然后输出指针对应的值
}
//指针刚开始指向第一个元素的上面
}
}
2.5.HashSet数组加链表存储
添加元素的过程:HashSet为例:
我们向HashSet中添加元素a,首先调用元素α所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
如果此位置上没有其他元素,则元素α添加成功。—>情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
如果hash值不相同,则元素α添加成功。—>情况2 如果hash值相同,进而需要调用元素α所在类的equlas()方法:
equals()返回true,元素α添加失败 equals()返回false,则元素α添加成功。—>情况2
对于添加成功的情况2和情况3而言:元素α与已经存在指定索引位置上数据以链表的方式存储。jdk 7 ︰元素α放到数组中,指向原来的元素。
jdk 8 ∶原来的元素在数组中,指向元素a
2.6.LinkedHashSet,TreeSet的简要描述
LinkedHashSet:在原有的结构上添加了一对指针,指向前一个和后一个元素。
TreeSet:
1.向Treeset中添加的数据,要求是相同类的对象。
2.两种排序方式:自然排序(实现Comparable接口)和定制排序(Comparator)
3、Map接口的常用方法和底层分析
3.1.关于key-value的描述
Map中的key:无序的、不可重复的,使用Set存储所有的key
Map中的value:无序的、可重复的,使用Collection存储所有的vaLue
一个键值对: key-value构成了一个Entry对象。
Map中的entry:无序的、不可重复的,使用Set存储所有的entry
3.2. HashMap的底层实现原理
HashMap的底层实现原理
以jdk7为例说明:
HashMap map = new HashMap():
在实例化以后,底层创建了长度是16的一维数组Entry[ ] table…可能已经执行过多次put. . .
map.put( key1 , vaLue1 ):
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1添加成功。----情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals( key2)
如果equals()返回false:此时key1-value1添加成功。----情况3
如果equals()返但true:使用value1替换value2。
补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
在不断的添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来.
jdk8相较于jdk7在底层实现方面的不同:
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk 8底层的数组是:Node[ ],而非Entry []
3.首次调用put()方法时,底层创建长度为16的数组
4.jdk7底层结构只有:数组+链表。jde8中底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度〉64时, 此时此索引位置上的所有数据改为使用红黑树存储。
3.3.Map集合源码的几个重要常量
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
DEFAUL T_LOAD_FACTOR: HashMap的默认加载因子:0.75
threshold:扩容的临界值,=容量填充因子:16 0.75 =>12
TREEIFY_ THRESHOLD: Bucket中链表长度大于该默认值,转化为红黑树:8M工N_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
3.4.Map集合的常用方法
// object put(object key,object value):将指定key-value添加到(或修改)当前map对象中
// void putAll(Map m):将m中的所有key-value对存放到当前map中
// object remove(object key):移除指定key 的key-value对,并返回value
// void clear():清空当前map中的所与数据
// object get(object key):获取指定key对应的vaLue
// boolean containskey(object key):是否包含指定的key
// boolean containsvalue(object value):是否包含指定的vaLueint size():返但map中key-value对的个数
// boolean isEmpty():判断当前map是否为空
// boolean equals(object obj):判断当前map和参数对象obj是否相等
// set keyset():返回所有key构成的Set集合
// coLlection values():返回所有value构成的CoLLection集合
// set entrySet():返回所有key-value对构成的Set集合
4.Collections工具类的一些方法
// reverse(List):反转List中元素的顺序
// shuffle(LTst):对List集合元紊进行随机排序
// sort(List)根据元素的自然顺序对指定list集合元素按升序排序
// sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
// swap(List, int,int):将指定list集合中的i处元素和j处元素进行交换
// object max(collection):根据元素的自然顺序,返回给定集合中的最大元素
// object max(collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
// object min(collection)
// object min(collection,Comparator)
// int frequency(collection,object):返回指定集合中指定元素的出现次数
// void copy(List dest,List src):将src中的内容复制到dest中
// boolean replaceALl(List list,object oldval,object newVaL):使用新值替换List对象的所有旧值
5.补充一张图