Collection接口方法
* 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().
//1.contains(Object obj):判断当前集合中是否包含obj
//在判断时会调用obj对象所在类的equals()。
coll.add(123);
System.out.println(coll.contains(new Person("Jerry",20)));//false -->true
@Override
public boolean equals(Object o) {
System.out.println("Person equals()....");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
//把123放入new对象所在类的equals方法形参
Iterator迭代器接口
内部方法:hasnext()和next()
调用后者前要用前者检测下一条记录是否有效,否则直接调用next()会抛出NoSuchElementException异常
- 使用Iterator遍历collection
while(iterator.hasNext()){
System.out.println(iterator.next());
}
错误方式一:
nosuchelementexception空指针、间隔输出
Iterator iterator = coll.iterator();
while(iterator.next() != null){
System.out.println(iterator.next());
}
错误方式二:
死循环,每次实例化后都会生成一个指向容器顶部的iterator指针
while(coll.iterator().hasNext()){
System.out.println(coll.iterator().next());
}
Collection子接口:List
List接口的实现类常用的有:ArrayList、LinkedList和Vector
-
|----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
-
|----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
-
|----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
jdk 8中ArrayLis底层
:变长数组
Object[] elementData初始化为{},第一次调用add时才创建了一个长度为10的数组。扩容方面:默认扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中
LinkedList底层
:双向链表,内部没有声明数组,而是定义了Node类型的first和last,用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构。
vector底层
:大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。扩容方面:默认扩容为原来数组的两倍。
增强for循环
List接口常用方法
Collection子接口:Set接口
- |----
Set接口
:存储无序的、不可重复的数据 -->“集合”
- |----
HashSet
:作为Set接口的主要实现类;线程不安全的;可以存储null值 - |----
LinkedHashSet
:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。对于频繁的遍历操作,LinkedHashSet效率高于HashSet. - |----
TreeSet
:可以按照添加对象的指定属性,进行排序。
向hashset中添加元素的过程
添加过程注释:
- 若此位置已有其他元素(或以链表形式存在多个),则比较元素的hash值:存在hash值不同但通过某种算法被分为同一索引位置的可能。(注:如果使用率超过0.75,底层数组会扩容为原来的二倍)。
- 如果hash值相同,需要调用元素a所在类的equals()方法: 存在由于hashcode计算方法设计出现的偶然情况(两个截然不同的实例有可能在逻辑上是相等的),如
a.name=jack (1) a.age=13(2) hashcode 1+2=3
b.name=ann(2) b.age=32(1) hashcode 2+1=3
通过equals来判断name和age是否相等
~
所以重写的hashCode()和equals()需要尽可能保持一致性:
相等的对象必须具有相等的散列码。
HashSet 集合判断两个元素相等的标准:
两个对象通过hashCode() 方法比较相等,并且两个对象的equals()方法返回值也相等。
LinkedHashSet:
是hashset的子类,插入性能略低于hashset,频繁遍历操作效率更高,使用双向链表维护元素次序。
Map的实现类结构
|----Map:双列数据,存储key-value对的数据 —类似于高中的函数:y = f(x)
||----HashMap
:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value
|||----LinkedHashMap
:保证在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
对于频繁的遍历操作,此类执行效率高于HashMap。
||----TreeMap
:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序
底层使用红黑树
||----Hashtable
:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
|||----Properties
:常用来处理配置文件。key和value都是String类型
HashMap的底层
:
数组+链表 (jdk7及之前)
数组+链表+红黑树 (jdk 8)
Map结构的理解:
- Map中的key:无序的、不可重复的,使用Set存储所有的key —> key所在的类要重写equals()和hashCode() (以HashMap为例)
- Map中的value:无序的、可重复的,使用Collection存储所有的value —>value所在的类要重写equals()
- 一个键值对:key-value构成了一个Entry对象。
- Map中的entry:无序的、不可重复的,使用Set存储所有的entry
HashMap底层实现原理
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
JDK7:数组+链表
实例化HashMap时,会创建一个长度(哈希表初始容量)为Capacity的Entry数组,存放元素的位置称为桶(具有索引)。Entry对象带一个引用变量,用于指向下一个元素形成Entry链,元素插入(7上头插),添加过程同hashset。
扩容:当超出临界值(且要存放的位置非空)时。
默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。是一个非常消耗性能的操作。
JDK8:数组+链表+红黑树
实例化HashMap时,会创建一个长度为InitialCapacity的Node数组,存放元素的位置称为桶(具有索引)。Node对象带一个引用变量,可能会形成Node链或变为TreeNode对象生成TreeNode树。
扩容同上
Treeify树形化:当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成红黑树,结点类型由Node变成TreeNode类型。
总结:
jdk8 相较于jdk7在底层实现方面的不同
- new HashMap():底层没有创建一个长度为16的数组
- jdk 8底层的数组是:Node[],而非Entry[]
- 首次调用put()方法时,底层创建长度为16的数组
- jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。
形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)
当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。
**LinkedHashMap的底层实现原理**
是HashMap的子类,与LinkedHashSet类似。
LinkedHashMap可以维护Map 的迭代顺序:迭代顺序与Key-Value 对的插入顺序一致
**hashtable**
HashMap的底层实现原理?
HashMap 和 Hashtable的异同?
1.HashMap与Hashtable都实现了Map接口。由于HashMap的非线程安全性,效率上可能高于Hashtable。Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供外同步。
2.HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
3.HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
4.Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
Collections工具类
Collections 是一个操作Set、List和Map 等集合的工具类
Collection 和 Collections的区别?
Collection是集合类的上级接口,继承于他的接口主要有Set 和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作.