Java集合类

java的集合类:
数组可以保存基本数据和对象(只保存对象的引用变量)但数组长度是不可变的,只能保存数量不变的数据,集合只能保存对象(同样只保存对象的引用变量),长度可变,可以保存数量变化的数据和具有映射关系的数据(关联关系 key-value)
在这里插入图片描述

集合的根接口:Collection
Collection就是体现上面介绍作为容器的方法。
遍历集合:
1、用foreach循环遍历
2、用Iterator遍历器遍历
A、hasNext():判断是否有下一个。
B、Next()如果有,取出下一个
C、remove()删除刚刚取出的元素
面试题:Enumeration:古老,没有remove方法,方法名长,淘汰,被Iterator代替
3、Collection继承了Iterator接口,1.8开始,Iterator新增了forEachRemaining(Consumer action)方法。因此,Collection对象可以使用Lambda表达式去遍历 ,语法如下:
对象.forEachRemaining(Lambda表达式创建Consumer的实例)

使用Predicate(函数式接口)操作集合:
Collection集合方法:removeIf(Predicate filter) 该方法将会批量删除符合filter条件的所有元素。相当于传入一个lambda表达式作为参数过滤集合。如:
集合名.removeIf.(ele -> ((String)ele).length() < 10) 即删除掉集合中长度小于10的字符串。
Predicate的方法:test() Predicate对象.test(obj) 判断obj是否满足Predicate对象指定条件。

Set:基本等同于Collection,增加了2个要求:
1、元素不允许重复
2、元素是无序的
Set的实现类:HashSet和TreeSet

HashSet
特征:
1、元素不允许重复
2、元素是无序的
3、快速存、取数据。

使用hash算法来存储集合中的元素,最大的特征就是:“快”——Set最常用的实现类就是HashSet.
HashSet判断两个元素相等:
1、要求两个对象的hashCode()返回值相等
2、要求两个对象通过equals比较相等
hashCode方法用于给HashSet、HashMap等需要Hash算法的程序调用的,作为对象的标识
重写hashCode方法:
1、所有参与equals比较的属性field,都要参与hashCode的计算
计算规则:
实例变量的类型 计算方式
Boolean hashCode = f ? 0 : 1
整数类型的byte、short、char、int hashCode = (int)f
Long hashCode = (int)(f ^ f(f >>> 32))
Float hashCode = Float.floatToIntBits(f)
Double Long i = Double.doubleToLongBits(f)
hasCode = (int)(1 ^ (1 >>> 32))
引用类型 hashCode = f.hashCode()

public boolean equals(Object obj)
	{
		//如果当前对象和被比较对象是同一个
		if (this == obj)
		{
			return true;
		}
		//obj不为null且obj是Goat对象
		if (obj != null &&obj.getClass() == Goat.class)
		{
			Goat target = (Goat)obj;
			return this.color.equals(target.color) &&
				(this.weight - target.weight) < 1e-6;//e-6 即10的-6次方
		}
		return false;
	}

2、计算出每个Field的hashCode值,然后将它们累加起来即可(为了避免多个变量相加产生偶然相等。累加之前要乘以一个质数,如31)
public int hashCode()
{
int prime = 31;
//所有参与equals比较的属性field,都要参与hashCode的计算
//如果是double,需要转换成int对象,如果是引用对象,直接使用this.变量 .hashCode()
return (int)(this.weight) * prime * prime + this.color.hashCode() * prime + this.xx.hashCode();
//如果总共有N个变量,则第一个数乘以N-1次方个prime,第二个数乘N-2次方个 prime,以此类推、
}
目的是让equals方法和hashCode方法是一致的。
Java系统提供的类,只要重写了equals方法,一般同时重写hashCode方法,因此,这些类只要通过equals比较返回true,那么他们的hashCode的值也相等。
HashSet为何快?性能选项。
HashSet是基于Hash表(本质是数组)实现的,源码也是先实现hashMap的父接口,相当于先实现hashMap,再将hashMap包装成一个value为空的集合,就得到一个set集合。
数组,在所有数据结构中是存、取数据最快的,数组变量:保存了数组对象的首地址(也就是和第一个元素的地址一致)
第i个元素地址=首地址 + i * 元素的大小(元素占字节的位数,如int,占4个字节)
当程序需要取第i个元素时,直接根据计算出来的地址去取值。
HashSet存元素的步骤:
1、HashSet会调用元素的hashCode()方法,该方法返回一个int值。
2、HashSet会根据元素的hashCode值计算该元素应该保存在HashSet底层数组的哪个位置。(即使第一个进来,也不一定放在第一个位置)将值对数组的长度进行取余,如值为100,数组长度为8,则100对8取余得4,位置就是索引为4的位置。
3、HashSet会到底层数组的该位置去检查,该位置是否已有元素。
A、如果该位置没有元素,直接把新元素保存到数组的该位置
B、如果该位置有元素,再调用equals方法比较两个对象是否相等,如果相等,添加失败,如果不相等此处就会形成链。
HashSet取元素的步骤:
1、HashSet会调用元素的hashCode()方法,该方法返回一个int值。
2、HashSet会根据元素的hashCode值计算该元素应该保存在HashSet底层数组的哪个位置。
3、HashSet会到底层数组的该位置去检查,检查该位置是否为要找的元素。如果该位置没有元素,则取出失败。
A、如果该位置确实保存了要找的元素,直接取出该元素即可
B、如果该位置的元素不是要找的元素,此时,就需要顺着该链、逐个去找。
链越长、查找性能越差。
HashSet底层数组越大,形成链条概率越小。
HashSet(int initialCapacity,float loadFactor) 有两个性能选项:
initialCapacity:初始大小,创建HashSet时底层数组的长度。默认值是16.数组长度总是比该数值略大的2的N次方,如设为20,即HashSet(20,0.5) 则比20略大的2的N次方的数为32,所以数组长度是32.
loadFacto:负载因子。默认值是0.75. 当元素个数/数组长度 >= 负载因子时,HashSet会将hash表容量(数组长度)扩大一倍。负载因子越大,(数组)利用率越高(越省内存),但形成链条概率越大。负载因子越小,数组利用率越低(越耗内存),形成链条的概率越小。

LinkHashSet:是HashSet的子类,因此与HashSet功能完全相同。
LinkHashSet会维护链(额外开销、因此略慢于HashSet),用于记住元素的添加插入顺序,遍历LinkedHashSet集合的元素,LinkedHashSet将元素添加顺序访问集合里的元素。

TreeSet:
TreeSet是基于“红黑树”实现的。“红黑树”是半平衡的排序二叉树。
特征:
1、元素不允许重复
2、元素有序
比HashSet要慢!
TreeSet实现了SortedSet,因此TreeSet会对元素按从小到大排列。
TreeSet的集合元素是排序 :由小到大,通过调用所添加元素的CompareTo方法或根据Comparator实现和集合元素进行比较,若大于元素则返回1,若等于该元素则返回0,若小于该元素则返回-1.

TreeSet比较元素大小:
自然排序:元素本身就可以比较大小—元素的类型实现了Comparable接口。并实现该接口中的compareTo方法。
自定义的类型,需要用implements 实现Comparable接口,并重写compareTo方法。
定制排序:不要求元素本身可比较大小。
但此时要求创建TreeSet时传入Comparator对象,该对象负责比较元素的大小。
无论如何:TreeSet要求集合元素只能是同一个类型!
TreeSet怎么判断两个元素相等?
只要两个元素通过compareTo(自然排序)或者compare(定制排序)比较返回0,TreeSet就认为它们是相等的。

TreeSet中添加元素,TreeSet会调用添加元素的compareTo方法或根据comparetor实现与集合中元素比较大小,然后根据红黑树结构找到它的存储位置,大概如:若返回1,则排序到比较元素后面的位置,若返回0,则集合中已有相同的元素,添加失败,若返回-1,则排序在比较元素前面的位置 。

EnumSet:创建时需要显示或隐式指定枚举类型,该集合中所有的元素必须是指定枚举类型的枚举值,该集合元素排序的顺序以枚举值在Enum类内定义的顺序来决定。
EnumSet在内部以位向量的形式存储,创建时指定枚举类型已经确定了内存的大小,存储数量,因此,占用内存非常小,运行效率很好。批量操作时,速度也非常快。

List集合:
元素可以重复
元素有序,按照添加顺序排列,第一个添加的元素索引为0…
由于Lsit的集合元素是有索引(下标)的,因此程序可通过下标去添加、删除、插入、替换指定位置的元素。
形象来看:List相当于一根竹子,每节只能装一个对象。
Set集合支持的方法 ,List集合完全都支持!
List集合有一个额外遍历集合的方法:可根据索引来遍历,让索引从0~size() - 1
Set他原来支持的3种遍历方式,用在List也完全没问题。

ArrayList:是List集合最常用的实现,基于Object[]数组的实现,因此性能非常好。底层封装了一个动态的、允许再分配的Object[]数组,创建对象时,传入的initialCapacity参数设置该数组的长度,当添加元素超出了该数组的长度时,它们的initialCapacity会自动增加1.5倍。
如果不指定initialCapacity长度,则默认为10。
如果一开始就知道要添加多少元素,可以在创建时就指定initialCapacity大小,更省内存。
如果要添加大量的元素,可以调用ArrayList对象的方法ensureCapacity(int min Capacity)方法一次性地增加initialCapacity,避免加满元素后重新分配的次数提高性能。
也可以调用对象方法trimToSize()将底层Object[]数组长度调整为当前元素的个数,节省存储空间。

面试题:Vactor和ArrayList:
ArrayList和Vectory的底层实现和用法上几乎相同,底层都基于Object[]数组实现
Vector比较古老,线程安全,性能差,被ArrayList代替,所以不使用。

Stack(栈):vector子类,只有一个口,后入的元素先出,先入的元素会在栈底部,最后添加的元素在栈顶部。有如下方法:
Peek():返回栈顶元素,不取出
Pop():弹出栈顶元素,取出
Push():放入元素,在栈顶

固定长度的List:
Arrays工具类的方法asList(Object…a)会把一个数组或指定个数的对象转换成一个固定长度的List集合,该List集合类是Arrays的内部类。 Arrays$ArrayList

LinkedList:实现了List接口和Deque接口,因此List和Deque支持的操作它都支持,可以通过索引随机访问集合的元素,也可以当做栈、队列等使用。
但ArrayList和ArrayDeque内部以数组的形式来保存集合中的元素,而LinkedList内部以链表的形式来保存集合中的元素,访问元素时需要逐个比较,因此性能较差。但插入、删除元素时性能比较好。
方法是最多的,List支持的方法和Deque支持的所有方法,它都支持。

Queue集合:队列,从尾部(下面)进入,顶部(上面)取出,即先进先出(FIFO)
Add(Object e):将元素加入队列的尾部
Element():获取头部的元素,但不删除
Offer():将元素加入队列的尾部,有容量限制时,该方法更好
Peek():获取队列头部的元素,不删除元素,空队列会返回null
Poll():获取队列头部的元素,删除元素,空队列返回null
Remove()获取队列头部的元素并删除

priorityQueue实现类:保存队列顺序并不按照加入顺序排列,而是按照元素大小进行排序,分为自然排序(元素实现Compareble接口)和定制排序(创建时传入Comparator实现)。,违反了队列先进先出最基本的规则。

Deque与ArrayDeque
Deque代表双端队列,既是栈,也是队列。
ArrayDeque是Deque的实现类,也是基于数组实现,因此性能非常好。双端队列可以从两端分别添加或取出元素。

面试题:Vector的子类stack:被Deque代替。
Stack是线程安全,性能差,Deque双端队列,可以通过两端添加或取出元素操作队列,更灵活,Deque是线程不安全的,性能更好。
主要作为2个场景:
栈:
Push(元素)
Pop()
Peek() 获取最上面的元素,但并不弹出。
队列
Offer(元素) 入队
Poll() : 出队
Peek() 获取队头的元素,但并不出队。

Colletion8集合归纳:6个接口 + 6个实现类 + 3个工具接口(Iterator、Comparable、Comparator)

Map根接口。地位与Colletion平等。集合元素总是以key-value键值对成对出现,每个key-value叫一个Entry。Entry是Map的内部类,一个Entry封装了一对key-value对,Key、value存在单向1-1的关系,通过key总可以找到唯一的value。

作用:用于存储具有关联关系的数据。
Map的特征:
1、key不允许重复。所有的KEY通过equals比较一定返回false,如果第二次放入的key与第一次Key重复,后放入的value会覆盖之前的value。
2、key是无序的
所以Set的集合元素和Map对Key的要求,是完全一样的。
实际上:如果把Map的value都当成空处理,此时,Map就只有key,这些key就组成了Set集合。所以java的Set集合,其实都是靠Map集合实现。将Map集合的value当成空,只看key部分。
如:
Map<String,Double> m = new HashMap<>();// 元素成对出现,所以需要写两个泛型
m.put(“语文”,89.5);//添加元素用put
System.out.println(m);//{语文=89.5}
m.put(“语文”,92.5);
System.out.println(m);//{语文=92.5}
第二次添加重复的key时,能添加进去,最后添加的Key对应的value值会覆盖原先添加的value.
【备注】:Map不能直接用foreach来遍历,甚至不能直接用iterator遍历。但是可以改为对Map的所有key进行遍历。接下来即可通过key来访问value

HashMap
特征:
1、key不允许重复
2、key是无序的
3、快速存、取数据。
最大的特征就是:“快”——Map最常用的实现类就是HashMap.
HashMap判断两个key相等:
1、要求两个key的hashCode()返回值相等
2、还要求两个key通过equals比较相等
hashCode方法用于给HashSet、HashMap等需要Hash算法的程序调用的,作为对象的标识
Java系统提供的类,只要重写了equals方法,一般同时重写hashCode方法,因此,这些类只要通过equals比较返回true,那么他们的hashCode的值也相等。
HashMap为何快?性能选项。
HashMap是基于Hash表(本质是数组)实现的
数组,在所有数据结构中是存、取数据最快的,数组变量:保存了数组对象的首地址
第i个元素地址=首地址 + i * 元素的大小
当程序需要取第i个元素时,直接根据计算出来的地址去取值。
HashMap存Entry的步骤:
1、HashMap会调用key的hashCode()方法,该方法返回一个int值。
2、HashMap会根据key的hashCode值计算该Entry应该保存在HashMap底层数组的哪个位置。(即使第一个进来,也不一定放在第一个位置)将值对数组的长度进行取余,如值为100,数组长度为8,则100对8取余得4,位置就是索引为4的位置。
3、HashMap会到底层数组的该位置去检查,该位置是否已有Entry。
A、如果该位置没有entry,直接把新entry保存到数组的该位置
B、如果该位置有entry,会调用key的equals方法比较是否相等,如果相等,会替换掉value值,若不相等此处就会形成链,JDK1.8之后,若链表的长度大于阈值(默认为8)时,将链表转化为红黑树,减少搜索时间。
HashMap取Entry的步骤:
1、HashMap会调用key的hashCode()方法,该方法返回一个int值。
2、HashMap会根据key的hashCode值计算该Entry应该保存在HashMap底层数组的哪个位置。
3、HashMap会到底层数组的该位置去检查,检查该位置是否为要找的Entry。
A、如果该位置确实保存了要找的Entry,直接取出该Entry即可,取出Entry的value即可
B、如果该位置的Entry不是要找的Entry,此时,就需要顺着该链、逐个去找。
链越长、查找性能越差。
HashMap底层数组越大,形成链条概率越小。
HashMap(int initialCapacity,float loadFactor) 有两个性能选项:
initialCapacity:初始大小,创建HashMap时底层数组的长度。默认值是16.数组长度总是比该数值略大的2的N次方,如设为20,即HashMap(20,0.5) 则比20略大的2的N次方的数为32,所以数组长度是32.
loadFactor:负载因子。值为size(当前元素个数)/容量大小
负载极限:是一个0~1的数值,默认值是0.75. 当负载因子,即:元素个数/容量大小 >= 负载极限时,HashMap会将hash表容量(数组长度)扩大一倍。负载极限越大,数组利用率越高(越省内存),但形成链条概率越大,形成链条影响查询速率。负载极限越小,数组利用率越低(越耗内存),形成链条的概率越小,查询效率越高。
面试题:HashMap和HashTable的区别:
HashTable是线程安全的,HashMap是线程不安全的,因此性能交好
HashTable不允许使用null作为key和value,而HashMap可以使用null作为key和value。

面试题:HashMap和HashSet的性能选项:
HashSet和HashMap都基于Hash表实现的,HashSet底层也是先实现HashMap的一个接口,

LinkHashMap:是HashMap的子类,因此与HashMap功能完全相同。
LinkHashMap会维护链(额外开销、因此略慢于HashMap),使用双向链表维护key-value对的顺序,用于记住元素的添加插入顺序,遍历LinkedHashSet集合的元素,LinkHashMap将元素添加顺序访问集合里的元素。

TreeMap:
TreeMap是SortedMap的实现类,基于“红黑树”实现的。“红黑树”是半平衡的排序二叉树。
特征:
1、元素不允许重复
2、元素有序
比TreeMap要慢!
TreeMap实现了SortedMap,因此TreeMap会对key按从小到大排列。
TreeMap的集合key是有序的 :由小到大

TreeMap比较key大小:
自然排序:key本身就可以比较大小—key的类型实现了Comparable接口。并实现该接口中的compareTo方法。自定义的类型,需要用implements 实现Comparable接口,并重写compareTo方法。
定制排序:不要求key本身可比较大小。但此时要求创建TreeMap时传入Comparator对象,该对象负责比较key的大小。
无论如何:TreeMap要求key只能是同一个类型!
TreeMap怎么判断两个key相等?
只要两个key通过compareTo(自然排序)或者compare(定制排序)比较返回0,TreeMap就认为它们是相等的。

Hashtable与Properties
Hashtable:被HashMap取代了,较老,线程安全,性能差,且Hashtable的key-value都不允许为null,否则程序会报错,
HashMap:线程不安全,性能好,key-value都允许为null。
Properties:是Hashtable的子类,可以非常方便的读、写属性文件。
Properties:继承了Hashtable,本质都是Map结构,但它的key-value都是String类型,
Properties相当于一个key-value都是String的Hashtable.
添加元素:setProperty(key,value)
取出元素:getProperty(String key)
写属性文件:store(OutputStream outputStream)方法
读属性文件:load(InputStream inputStream)方法

IdentityHashMap实现类:和HashMap基本一致,但比较两个key相等更严格,必须key==key才表示相等。

EnumMap:key的存储和EnumSet一致
Colletions工具类:所有的方法都是静态的
对集合进行排序操作:
Reverse(List list):反转指定List集合中元素的顺序
Shuffele(List list):对集合元素进行随机排序
Sort(List list):根据集合元素的自然顺序比较大小按升序进行排序
Sort(List list,Comparator c):根据指定Comparator产生的顺序对集合元素进行排序
Swap(List list,int i,int j):将List集合i处元素和J处元素进行交换
Rotate(List list,int distance):当distance为整数,将list集合的后distance个元素“整体”移
到前面,为负数时,将list集合的前distance个元素“整体”移到后面,集合长度不变。
对集合进行查找、替换操作:
Int binarySearch(List list,Object key):使用二分搜索法搜索指定的List集合,获得指定对象在 List集合中的索引。此处list集合中的元素必须已经处于有序状态
Object max(Conllection coll):根据自然排序顺序取出集合最大元素
Object max(Collection coll,Comparator c):根据定制排序取出集合最大元素
Object min(Conllection coll):根据自然排序顺序取出集合最小元素
Object min(Collection coll,Comparator c):根据定制排序取出集合最小元素
Void fill(List list,Object obj):使用指定元素obj替换list集合的所有元素
Int frequency(Collection c,Object o):返回集合中指定元素o出现的次数
Int IndexOfSubList(List source,List target):返回子List对象在父List对象中第一次出现的位置 索引,若没出现,返回-1
Boolean replaceAll(List list,Object oldVal,Object newVal)L使用新值newVal替换集合所有旧值 oldVal

同步控制,将集合包装成线程安全的集合:
synchronizedXxx():如synchronizedList(new ArrayList())可以将list集合包装成线程安全的,
synchronizedSet(new HashSet())可以将Set集合包装成线程安全的,
synchronizedMap(new HashMap())可以将Map集合包装成线程安全的
集合中的10个实现类,出了properties,其余的9个实现类都是线程不安全的。
多线程环境下,即使需要使用线程安全的集合,同样不需要使用Vector、Stack、Hashtable——使用synchronizedXxx(集合)方法即可将线程不安全的集合,包装成线程安全的集合。
检查集合的方法,得到类型安全的集合:checkXxx

设置不可变集合
emptyXxx方法:返回空的、不可变的集合对象,可以是List、Set、Map等
singletonXxx(元素):得到只包含一个元素的不可变的集合的方法,可以是List或Map
ummodifiableXxx(集合):得到有集合元素的不可变的集合:将原来的集合变成不可变的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值