- 最顶层接口
Collection:存储单个值
Map:存储键值对 key-value
- Collection的子接口
List:可以存储重复数据、可以存储null值、插入有序
Set:不可存储重复数据、可以存储null值、插入无序
Queue:不可存储重复数据、不可存储null值、插入无序
- List接口的主要实现类
ArrayList:底层结构为数组 ,查询效率高(下标)、修改效率低
LinkedList:底层结构为双向链表,查询效率低、修改效率高
- ArrayList的使用
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList1 = new ArrayList<>();
arrayList1.add(45);//添加指定类型 boolean add(E e)
arrayList1.add(34);
arrayList1.add(55);
arrayList1.add(55);
arrayList1.add(2);
ArrayList<Integer> arrayList2 = new ArrayList<>();
arrayList2.add(55);
arrayList2.add(3);
arrayList1.removeAll(arrayList2);//差集,删除给定集合的元素
arrayList1.retainAll(arrayList2);//交集,不同对象调此方法结果不同
arrayList1.removeAll(arrayList2);
arrayList1.addAll(arrayList2);//不重复并集
Integer[] array = (Integer[])arrayList1.toArray();//集合转化为数组
arrayList1.contains(55);//检查是否存在给定元素
arrayList1.remove(Integer.valueOf(55));//remove() 两种删除方式:下标、对象
arrayList1.set(0,34);//set() 修改 返回下标为index的原存储值
Iterator<Integer> iterator = arrayList1.iterator();//创建迭代器实例(通过集合对象调用iterator()方法)
//访问集合
while (iterator.hasNext()){//判断集合是否还能继续遍历
Integer value = iterator.next();//获取元素
System.out.println(value);
}
for (Integer i:arrayList1) {//for each遍历方式底层实现方式迭代器
System.out.println(i);
}
for (int i = 0; i < arrayList1.size(); i++) {//size() 统计集合元素个数
System.out.println(arrayList1.get(i));//get() 获取元素
}
}
}
- 迭代器
是一种设计模式,提供了一种方法来访问容器(集合)
迭代器的使用(具体可以看ArrayList的使用):
1、创建迭代器实例(通过集合对象调用iterator()方法)
2、判断集合是否还能继续遍历
3、获取元素
迭代器的特点:
1、数据的遍历从前往后
2、hasNext()和next()要交替使用
- LinkedListd的使用
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.add(13);
linkedList.add(11);
linkedList.add(45);
linkedList.add(1);
linkedList.offer(2);//添加元素
linkedList.get(1);
linkedList.element();//获取队头元素即第一个元素
linkedList.peek();//获取队头元素即第一个元素
linkedList.remove(11);//若不传参数则删除第一个元素
linkedList.pop();//删除队头元素即第一个元素
linkedList.poll();//删除队头元素即第一个元素
linkedList.indexOf(13);//找到元素在集合中的位置
linkedList.toArray();//转成数组
linkedList.subList(1,2);//截取指定范围的子集合
}
}
-
ArrayList与LinkedList异同点
适用场景
查询操作多的场景下使用ArrayList
变更(插入、删除) 多的场景下使用LinkedList
不同点
1.ArrayList需要扩容(1.5倍扩容),LinkedList不需要扩容
2.*ArrayList底层数据结构为数组,LinkedList底层数据结构为双向链表
3. *ArrayList查找效率高,LinkedList插入和删除效率高
4. LinkedList实现Deque接口,提供了头插尾插头删尾删等方法
5. ArrayList有默认值10,LinkedList没有默认值
相同点
1.可以存放重复性数据、可以存储null值、插入有序
2.可以实现克隆和序列化
3.都可以使用ListIterator迭代器
- Map接口
哈希结构:通过关键码(key)找到值(value)的结构,底层数组,对数据的访问通过哈希函数(键和值的映射关系)
哈希函数:好的哈希函数能够使值均匀地分布在哈希结构中
两种生成哈希函数方式:①直接寻址法 f(x) = kx + b(k和b是常数)
②除留余数法 f(x) = x mod m(m是常数,一般取素数或哈希长度,m<=哈希长度)
哈希冲突:当通过哈希函数计算出来的值总会有相同情况,此时映射到数组的同一位置,即产生了哈希冲突
两种哈希冲突的解决方式:①链地址法 ②线性探测法
- HashMap的使用
public class HashMapDemo {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
//添加元素
hashMap.put("黄晓明", "杨颖");
hashMap.put("邓超", "孙俪");
hashMap.put("黄磊", "孙莉");
/**
* key插入无序
* key不能重复,value可以重复
* 当插入的键值对中的key和集合中的key相同时,会覆盖掉之前的值
* key可以为null,value可以为null
*/
//map三种遍历方式
System.out.println("通过键值对遍历:");
Iterator<Map.Entry<String, String>> iterator = hashMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + ":" + value);
}
System.out.println();
System.out.println("通过键遍历:");
Iterator<String> iterator1 = hashMap.keySet().iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
System.out.println();
System.out.println("通过值遍历:");
Iterator<String> iterator2 = hashMap.values().iterator();
while (iterator2.hasNext()){
System.out.println(iterator2.next());
}
}
}
- HashMap源码分析
- HashMap与Hashtable的异同点
不同点
1.继承的父类不同,因此特有的方法不同
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。
2.线程安全不同
HashMap是线程不安全的, Hashtable中每个方法都加了synchronized关键字,因此是线程安全的。
HashMap实现线程安全:Collections.synchronizedMap(hashMap);
3.key和value是否允许null值
HashMap中的key和value都允许为null,key只允许一个null值,Hashtable不允许key和value为null。
4.hash函数与索引的计算方式不同
( hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值)
Hashtable的hashSeed与hashCode进行异或操作计算hash值,而HashMap使用hashCode进行一系列异或操作计算出hash值。
Hashtable在求hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,用与运算。
5.数组初始化容量不同
Hashtable在不指定容量的情况下的默认容量为11,而HashMap为16。Hashtable不要求数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
6.扩容机制不同
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
7.迭代方式
HashMap只有迭代器,Hashtable可以使用迭代器、枚举遍历方式
8.效率不同
单线程下HashMap效率比Hashtable高
相同点
1.实现接口:实现Map接口,可克隆,可序列化
2.迭代器:使用Iterator迭代器
3.存储结构:使用哈希表存储
4.重复性:key不能重复,value值可以重复
- HashSet特点
基于HashMap实现、可以存储null值、数据插入无序、数据不可重复
因事先Set接口,则存储单个值,为HashMap中的key,因此插入无序
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}//add方法没有使用value,因此存储单个值而不是键值对
适用场景:数据去重(插入无序)
-
LinkedHashMap特点
继承自HashMap,但数据插入有序(Entry节点添加了两个属性after、before,底层实现双向循环链表),其他与HashMap基本一样 -
LinkedHashSet特点
继承自HashSet,插入有序,存储单个值,数据不能重复,可以存储null值
//HashSet的构造函数之一
//没有访问修饰符,不能被直接调用,即专门为LinkedHashSet提供的
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}//底层调用LinkedHashMap
适用场景:数据去重(插入有序)
- TreeMap特点
数据按照特定规则排序,底层实现是红黑树,实现Comparator接口,key不能为null
要想按照自习的方式排序需写一个比较器作为参数传入
- TreeSet特点与适用场景
底层实现TreeMap,存储单个值,不能存储null值(因为需要比较),不能重复,按照给定规则排序
适用场景:数据去重,按照特定规则排序
- Queue接口的实现类:PriorityQueue
队头元素总是最小元素(若想得到最大元素需写一个比较器作为参数传入)
特点:不能存储null值,数据可以重复