java类集(JDK1.2,java.util包): lang包:语言有关的所有包,io包:输入输出包,传统IO,util包:java类集
本质:动态对象数组
核心接口:Collection:针对单个对象的处理
public interface Collection 《E》 extends Iterable<E>
public interface Iterable<T>:实现了此接口,可以使用for-each循环
Iterator <T> iterator(): JDK1.5以前直接在Collection接口中定义
Iterator:集合遍历类。 迭代器模式
List extends Collection :允许数据重复,
Set extends Collection :不允许数据重复
List接口(80%):E get(int index):根据索引取得数据
E set(int index):修改指定索引元素的内容,返回修改前内容
在list接口下有三大实现类:
1.ArrayList实现类(90%):底层为数组
2.Vector实现类(JDK1.0):底层为数组
3.LinkedList实现类(8%):底层为双链表
List集合与简单Java类:如果你的简单java类要和List类集合搭配起来时,如
remove(),contains()等方法需要覆写equals()方法来比较属性值
ArrayList与Vector区别:
Vector JDK1.0 ArrayList JDK1.2
Vector采用同步处理,效率低,线程安全(synchornized锁)
ArrayList采用异步处理,效率高,线程不安全
ArrayList支持Iterator、ListIterator、foreach输出
Vactor支持Enumeration、Iterator、ListIterator、foreach输出
ArrayList与LinkedList区别:
ArrayList采用数组实现,LinkedList采用双链表
ArrayList适用于频繁查找元素场景,LinkList适用于频繁修改元素场景
Set集合接口:
本质为没有Value值的Map,先有的Map集合才有的Set
两大集合子类:
HashSet:无序存储,实际上就是HashMap:底层为数组,不允许重复元素
Set接口: Set<>set=new HashSet();
允许为null,且不能重复,元素乱序存储
判断重复依据Hashcode()+equals()方法
Object: public native int hashcode():返回对象地址的hash码
两个对象(第三方类)相等判断:必须hashCode()和equals()均返回为true才认为相等
TreeSet:有序存储,实际上就是TreeMap:底层为红黑树
不允许为空,有序存储,顺序自定义
TreeSet判断重复元素由CompareTo()实现。
自定义类要使用TreeSet,必须覆写Comparable接口,无需再覆写equals,hashCode
public int compareTo(T o):
返回>0,当前对象>目标对象
返回=0,当前对象=目标对象
返回<0,当前对象<目标对象
集合输出:
四种方式:Iterator(推荐)、ListIterator、Enumeration、for-each循环
Iterator:迭代器输出(List,Set都有 只能单向输出)
a.hasNext():判断是否有下个元素
b.next():取得当前元素
c.remove():删除当前元素
fail-fast(快速失败)(数据安全性):当fail-fast机制在遍历一个集合的时候,结合的结构被修改,会抛出并发修改异常
并发修改:当一个线程在遍历集合的时候,另一个线程修改集合内容
如何产生快速失败:public transient int modCount=0;
描述集合被修改的次数:modCount
遍历时会检查修改次数
当修改次数不等于已记录的被期望的修改次数,就会报错
被期望的修改次数在调用迭代方法时被赋值
产生并发修改异常的类集:ArrayList、HashSet、HashMap
如何解决:a并发遍历集合时,不要修改集合neir
b使用file-safe类集(CopyOnWriteList、ConcurrentHashMap)
fail-safede集合全部是线程安全集合
CopyOnWriteArrayList使用Lock锁实现线程安全(IDK1.7之前的ConcurrentHashMap也采用Lock锁)
fail-safe任何对集合结构的修改都会在一个复制的集合上进行,因此不会抛出并发修改异常,因为原来的集合根本就没变
fail-safe机制有两个问题:
需要复制集合,产生大量的无效对象,开销大
无法保证读取的数据是目前原始数据结构中的数据
双向迭代器:ListIterator(List接口独有)
除了Iterator提供的方法外,自己拓展了hasPrevious():判断是否有上个元素
previous():取得上个元素
要想从后往前输出,必须先从前往后走一遍
Enumeration枚举输出,(Vactor类才有)
for-each输出
List集合中的自动扩容(ArrayList、Vector)
1.ArrayList(初始化时为空数组):
扩容策略:增加50% int newCapicity=oldCapicity +(oldCapicity>>1)
扩容后的容量为当前容量的1.5倍
2.Vector(初始化时大小为10):
扩容策略:增加一倍
默认扩容后容量为当前类集的2倍
动态扩容本质:调用Arrays.copyOf(elementData,newCapacity)创建新数组
Map:针对键值对对象处理(k=V)
一次保存两个对象,且两个对象的关系为key=value(键值对对象)
Map特点:可以通过key找到对应的value
常用方法:put(k key,v value):向map中追加数据
get(k key):根据key取得对应value,没找到返回null
keySet():返回所有key信息,保存在Set集合中(Key不能重复)
values():取得所有的value信息,保存在Collection集合中(Value可以重复)
entrySet():返回值是Set<Map,Entry<K,V>>将Map集合变为Set集合
Entry<K,V>:(方便Map集合的输出,以及元素的保存)Map集合内部接口,具体保存键值对对象,Map集合内部实际上是一个一个的Map.Entry对象
getKey():取得key对象
getValue():取得value值
HashMap子类(***********************):
HashMap允许Key,Value为空,value允许多个空,Key只允许有一个null
源码解析:
1.HashMap内部实现:数组+链表
数组又被分为一个一个桶(bucket),通过hash决定键值对在数组的地址,hash相同的键值对,以链表形式存储,当链表大小超过阈值(TREEFY_THRESHOLD-8),将其树化(红黑树)
构造方法:
//初始化默认负载因子:0.75f
this.loadFactor=DEFAULT_LOAD_FACTOR
HashMap采用lazy_load,在初次使用时对table初始化
put方法实际调用putval(int hash,K key,V value,boolean onlyIfAbsent,boolean evict)
hash:表示键值对hash码
onlyIfAbsent:表示当key重复时是否允许修改,默认是false,允许修改
evict:当前HashMap状态,false表示正在初始化阶段
putval():a.如果表格为null,resize方法会初始化它
b.resize方法负责创建初始化存储表格或者在容量不满足时需求扩充
c.键值对在哈希表中的位置(并不是key的hash码)避免哈希-碰撞 i=(n-1)&hash
哈希冲突解决方法:
1.开放地址法:
2.再散列(采用不同的哈希算法再次哈希)
resize():初始化时,桶大小为16
a.门限值=负载因子*容量
b.门限值通常以倍数进行调整(newTre=oldTre<<1),当元素的个数超过门限大小时调整Map
c.扩容后将老数组元素拷贝到新数组,扩容为主要开销
容量、负载因子:
public HashMap(int initialCpacity)
预设的容量大小需要满足>“预估元素数量/负载因子”同时是2的幂次方
负载因子:
a.不推荐改变,默认的负载因子符合通用场景需求
b.不要设置超过0.75的值,会显著增加哈希冲突,降低HashMap的性能,也不要设置太小的负载因子,会导致更加频繁的扩容,影响访问性能
树化:JDK1.8为什么引入树化
安全问题。当对象键值对冲突时,会放在同一个桶中以链表的形式存储,链表过长,严重影响存取的性能
当桶中元素超过8个的时候,调用treefyBin()尝试树化
如果容量小于MIN_TREEIFY_CAPACITY(64),会调用resize()扩容
容量大于MIN_TREEIFY_CAPACITY,才会树化改造
当链表变为红黑树后,元素删除n次后,如果红黑树的节点个数<UNTREEIFY_THRESHOLD(默认为6),在下一次resize后,又会将红黑树变为链表
Hashtable子类(JDK1.0,第一个存储二元偶对象的类)
Hashtable key,value均不允许为null
线程安全:在增删改等方法上加锁(synchornized,同Vector)
HashMap与Hashtable:
Hashtable是早期java类库提供的一个哈希表实现(JDK1.0),本身是同步的,不支持null值和键
由于同步导致的性能开销,所以已经很少被腿甲使用
HashMap JDK1.2 主要区别于HashMap 不是同步的,支持null值和键。通常情况下,HashMap进行put或get操作,可以达到常数时间的性能,所以它是绝大部分利用键值对存取场景的首选,比如实现一个用户ID和信息对应的运行时存储结构