1.集合的接口不提供任何成员变量(数据结构),只提供对数据操作的抽象方法,具体实现和数据结构的设计,要看具体子类
2.Collection,Map是直接父接口,他们定义的是最通用的接口方法
3.List,Set是 collection接口的子接口,他们在Collection的基础上 去提供自己独有的方法而set接口几乎完全 重新 声明 Collection接口,没增加任何接口方法,目的应该是 与 List共同 作为 Collection的子接口,便于开发把
4.List:有序,可重复,原因是它的实现类的数据结构是数组 和 链表
Set: 无序,不可重复,原因 它的实现类的数据结构是 哈希表和二叉树
5.Collection(单列数据)
1.通用方法
1、添加
add(Object obj)
addAll(Collection coll)
2、清空,删除集合
void clear()
remove(Object obj) :通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素
removeAll(Collection coll):取当前集合的差集
3、查询(是否包含某个元素)
boolean contains(Object obj):是通过元素的equals方法来判断是否是同一个对象
boolean containsAll(Collection c):也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。
4、获取有效元素的个数
int size()
5、是否是空集合
boolean isEmpty()
6、取两个集合的交集
retainAll(Collection c):把交集的结果存在当前集合中,不影响c
7、集合是否相等
boolean equals(Object obj)
8、转成对象数组
Object[] toArray()
9、获取集合对象的哈希值
hashCode()
10、遍历
iterator():返回迭代器对象,用于集合遍历
2.Iterator迭代器接口(只遍历 collection集合 )
1.一个迭代器,会对应一个集合的状态,会在内存中虚拟化一个集合,对此集合进行remove结束后,实际集合会
对应 迭代器集合,进行remove
2.Collection接口继承了java.lang.Iterable接口,里面iterator()方法,返回iterator迭代器对象
由 其子类 实现的,返回的是Iterator的 实现类 private class Itr implements Iterator<E>
3.集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
3.iterator迭代器方法 hasNext ,next ,remove,
4.在迭代的过程中,不能调用集合对象的remove方法删除对象,
因为这时集合结构发生了改变,迭代器必须重新获取
5.在迭代的过程中只能调用 迭代器的 remove方法
如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,
再调用remove都会报IllegalStateException。
6.foreach,遍历集合,底层是iterator
6.List
1.多了一些 根据 索引来 操作数据的方法(因为底层是线性的)
2.元素有序(不是大小顺序)、且可重复,集合中的每个元素都有其对应的顺序索引。
3.List接口方法:List 集合里添加了一些根据索引来操作集合元素的方法。
1.添加
add(int index, Object ele):在index位置插入ele元素
add方法是插入不是覆盖
addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
2.查询
get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
3.删除
Object remove(int index):移除指定index位置的元素,并返回此元素
4.修改
Object set(int index, Object ele):设置指定index位置的元素为else
5.截取子集合
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
4.ArrayList 动态数组
1.JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组
JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组
2.Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是
Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
3.属性
//默认容量的大小
private static final int DEFAULT_CAPACITY = 10;
//空数组常量
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认的空数组常量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
上面两个没啥区别,默认空数组常量 是调用无参构造的时候,赋给elementData的
空数组常量是 调用有参ArrayList(0) 赋值给 elementData
//存放元素的数组,从这可以发现 ArrayList 的底层实现就是一个 Object数组
transient Object[] elementData;
//数组中包含的元素个数
private int size;
//数组的最大上限
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
4.方法
1.get(index)
rangeCheck(index) 先判断是否越界
return elementData(index); 返回值
2.public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
} 无参构造 数组为 null
3.public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
构造方法,默认elementData是一个空数组,当我们指定初始容量大小就变成我们初始化大小
4.public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} 这两部会导致线程安全问题
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
如果是空数组,那么会将capcity赋值10,然后调用grow(10)去扩容,扩容调用的是Arrays.copy(原数组,长度),扩容后的数组大小是10
如果不是空数组,那么会调用 grow方法,判断是否要越界了,若是则扩容,扩容大小是1.5倍
grow方法扩容 newCapacity = oldCapacity + (oldCapacity >> 1); 原长度+原长度左移一位,就是1.5倍
5.总结(Vetor 比 ArrayList 多一个 扩容量capacityIncrement;)
1、ArrayList 创建时的大小为 0;当加入第一个元素时,进行第一次扩容时,默认容量大小为 10。
2、ArrayList 每次扩容都以当前数组大小的 1.5 倍去扩容。
3、Vector 创建时的默认大小为 10。
4.Vector 每次扩容都以当前数组大小的 2 倍去扩容。当指定了 capacityIncrement 之 后,每次扩容仅在原先基础上增加 capacityIncrement 个单位空间。
5、ArrayList 和 Vector 的 add、get、size 方法的复杂度都为 O(1),remove 方法的复杂度为 O(n)。
6、ArrayList 是非线程安全的,Vector 是线程安全的。
5.LinkedList:底层双向链表(add,remove特定元素用)
7.set
1.Set接口是Collection的子接口,set接口没有提供额外的方法
2.Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个
Set 集合中,则添加操作失败,因为 set接口的实现类 是 hash表 和 树
*3.hashSet
1.底层是hash表
hash表不是数组加链表,是为了 在 查询时不做比较,直接一步查出数据,
那么就要给每个数据一个关键字,key对key做hash,然后存入数组,
下次取数据时,直接计算元素hash,得到数组下标,就可以直接定位到具体元素,
如果直接用数组,那么得一个一个比较,这里说的不是通过下标查元素
2.散列函数得出数组下标 必须得根据数组的大小作为依据,使得计算出来的数组下标都在范围内
2.hash冲突:
元素在hash,散列函数计算后 得到的数组下标一样,就会导致一个桶无法存多个数据,那么
就得解决例如加链表,但是这样的查询速率会降低,所以散列函数的设计非常重要,要尽量设计的
分散一定,如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
2.HashSet 不是线程安全的
3.HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相
等,并且两个对象的 equals() 方法返回值也相等
*4.对应的类一定要重写equals()和hashCode(Objectobj)方法,以实现对象相等规则。
即:“相等的对象必须具有相等的散列码” ,equals相同 hashcode必须相同
5.向HashSet中添加元素的过程:
1.计算出hashcode值,通过散列函数,得到数组下标的位置
2.这个散列函数会与底层数组的长度相计算得到在数组中的下标
3.散列函数计算还尽可能保证能均匀存储元素,越是散列分布,该散列函数设计的越好
4.哈希冲突:先比较hash值,再比较equals,(其实直接比较equals就能知道元素是否相同)
因为hash值已经计算出来了,可以直接比较
1.若hash值都不相同,那么这个对象跟链表里面的元素都不相同加在最后面即可
2.若hash值相同,那么得比较equals(因为,equals相同,hashcode相同,所以hash相同,
不一定equals相同),相同,则链表中有相同的元素,value覆盖即可
若不同,则加在最后
4.LinkedHashSet(可以看起来 让 hashset 有序)
?1.LinkedHashSet 是 HashSet 的子类
2.LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,
但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
3.LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
4.LinkedHashSet 不允许集合元素重复
5.TreeSet
1.TreeSet 是 SortedSet 接口的实现类,TreeSet无序不可重复,但是可以排序
2.TreeSet底层使用红黑树结构存储数据
3.新增方法
Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement) ?
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)
4.TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序
5.TreeSet和TreeMap采用红黑树的存储结构
6.有序,查询速度比List快
7.
8.Map
1.Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应
的类,须重写hashCode()和equals()方法
2.添加、删除、修改操作: ?
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中的所有数据
?
3.元素查询的操作:
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value
int size():返回map中key-value对的个数
boolean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
4.元视图操作的方法:
Set keySet():返回所有key构成的Set集合 遍历集合
Collection values():返回所有value构成的Collection集合
Set entrySet():返回所有key-value对构成的Set集合 遍历集合 Set<Map.entry<K,V>>
5.
1.一个key-value构成一个entry
2.所有的entry构成的集合是Set:无序的、不可重复的
3.HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。
4.底层是数组加链表,不是hash表(hash表是一种数据结构,不是具体的实现),
hashmap是按 哈希表 的 一种实现
5.hashmap怎么解决hash冲突的:
1.如果产生hash冲突(add的时候,桶的位置已经有元素了)
链表的方式解决,循环比较,
1.若hash值都不相同,那么这个对象跟链表里面的元素都不相同加在最后面即可
2.若hash值相同,那么得比较equals(因为,equals相同,hashcode相同,所以hash相同,
不一定equals相同),相同,则链表中有相同的元素,value覆盖即可
若不同,则加在最后
2.没有出现hash冲突的元素,一定equals不同,存在不同桶中(hash值相同,数组下标一定相同)
6.JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)
JDK 8版本发布以后:HashMap是数组+链表+红黑树实现
解决的问题:数组长度太小没有扩容而链表太长导致的查询速度变慢
终究是一个 数组大小和链表长度的比例问题
7.HashMap的扩容
1.为什么要进行扩容
不是数组大小不够了,是数组的桶被占的越来越多,出现hash冲突的次数越来越多,
导致查询速率越来越小
2.扩容为什么是性能消耗最大的点:
原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize
3.扩容是越大越好吗
不是,当达到64了就得考虑是否把链表中的元素转换成红黑数了,是8就转
因为扩容越大,性能消耗越大
4.hashmap什么时候进行扩容
(1.8前后都是这样) 1.当数组元素达到 默认数组长度(一般为16)*0.75 = 12时 ,扩容一倍
然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作
所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能
5.1.8之后什么时候链表树形化
1.为什么要转红黑树
1.红黑树查找的时间复杂度是 O(logn) ;而链表查找元素的时间复杂度为 O(n),远远大于红黑树的 O(logn),
尤其是在节点越来越多的情况下,O(logn) 体现出的优势会更加明显;简而言之就是为了提升查询的效率。
2.为什么不一开始就用红黑树
1.TreeNode 需要占用的空间大约是普通 Node 的两倍
由 TREEIFY_THRESHOLD 的值(默认值8)决定的
2.当桶中节点数由于移除或者 resize 变少后,又会变回普通的链表的形式,
以便节省空间,这个阈值是 UNTREEIFY_THRESHOLD(默认值6)。
3.转换阈值 8 是怎么来的
1.反正体现了空间和时间的平衡,一般情况下由于 hash 计算的结果离散好的话,
那么红黑树这种形式是很少会被用到的,因为各个值都均匀分布,很少出现链表很长的情况。
千万分之一的概率
4.什么时候转红黑数
1.当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,
那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型
2.因为:数组没有达到64之前,可以通过扩容,达到效率提升,减少哈希冲突,而且扩容后,
出现哈希冲突的几率变低,那么链表的长度就不会再增,但是扩容的大小>=64了,就不会扩容了
因为再扩容,重新计算其在新数组中的位置,并放进去的消耗太大
8.JDK1.8相较于之前的变化
1.HashMap map = new HashMap();//默认情况下,先不创建长度为16的数组
2.当首次调用map.put()时,再创建长度为16的数组
3.数组为Node类型,在jdk7中称为Entry类型
4.形成链表结构时,新添加的key-value对在链表的尾部(七上八下)
5.当数组指定索引位置的链表长度>8时,且map中的数组的长度> 64时,此索引位置
上的所有key-value对使用红黑树进行存储。
9.HashMap源码中的重要常量
1.HashMap的默认容量,16
2.HashMap的最大支持容量,2^30
3.HashMap的默认加载(扩充)因子 0.75
4.扩充因子 可以自己设置
5.扩容的临界值,=容量*填充因子
6.TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值 8 ,转化为红黑树
7.UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值 6 ,转化为链表
8.MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。64
6.LinkedHashMap
hashmap的子类,在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
7.TreeMap 底层是红黑树
1.自然排序:类内部必须实现,comparable排序接口里面的int compareto(T t) 方法
2.定制排序:在构造方法时,得传入comparator接口的实现类
3.TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0
8.Hashtable
Hashtable是线程安全的
与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value
9.Properties
1.Hashtable 的子类,该对象用于处理属性文件
2.Properties 里的 key 和 value 都是字符串类型
3.存取数据时,建议使用setProperty(String key,String value)方法和
getProperty(String key)方法
4.有和流技术相结合的方法
5.读取文件中的数据,并保存到集合
load(Reader)
1.list-set的相互转换(list去重)
利用set集合特性保持顺序一致去重;
1.List<String> listNew = new ArrayList<String>(new TreeSet<String>(list));
2.List<String> listNew2 = new ArrayList<String>(new LinkedHashSet<String>(list))
9. Collections工具类
1.Collections 是一个操作 Set、List 和 Map 等集合的工具类
2.中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,
还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
3.排序操作:(均为static方法)
?reverse(List):反转 List 中元素的顺序
?shuffle(List):对 List 集合元素进行随机排序
?sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
?sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
?swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
4.查找、替换
?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.Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集
合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
集合的所有API
Collection
1.添加
add(Object obj)
addAll(Collection coll)
2、清空,删除集合
void clear()
remove(Object obj) :通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素
removeAll(Collection coll):取当前集合的差集
3、查询(是否包含某个元素)
boolean contains(Object obj):是通过元素的equals方法来判断是否是同一个对象
boolean containsAll(Collection c):也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。
4、获取有效元素的个数
int size()
5、是否是空集合
boolean isEmpty()
6、取两个集合的交集
retainAll(Collection c):把交集的结果存在当前集合中,不影响c
7、集合是否相等
boolean equals(Object obj)
8、转成对象数组
Object[] toArray()
9、获取集合对象的哈希值
hashCode()
10、遍历
iterator():返回迭代器对象,用于集合遍历
List(具备collection API)
List接口方法:List 集合里添加了一些根据索引来操作集合元素的方法。
1.添加
add(int index, Object ele):在index位置插入ele元素
add方法是插入不是覆盖
addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
2.查询
get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
3.删除
Object remove(int index):移除指定index位置的元素,并返回此元素
4.修改
Object set(int index, Object ele):设置指定index位置的元素为else
5.截取子集合
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
Set(和 collection 没有区别)
TreeSet
Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement) ?
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)
map
2.添加、删除、修改操作:
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中的所有数据
3.元素查询的操作:
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value
int size():返回map中key-value对的个数
boolean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
4.元视图操作的方法:
Set keySet():返回所有key构成的Set集合 遍历集合
Collection values():返回所有value构成的Collection集合
Set entrySet():返回所有key-value对构成的Set集合 遍历集合 Set<Map.entry<K,V>>
Collections工具类
3.排序操作:(均为static方法)
?reverse(List):反转 List 中元素的顺序
?shuffle(List):对 List 集合元素进行随机排序
?sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
?sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
?swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
4.查找、替换
?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 对象的所有旧值