集合框架list,set,map常见类及使用
List常见类及其区别
List是一个有序的集合接口。可以通过一个位置索引进行新增、删除、查找元素。注:它允许重复的元素
list中常见类:AbstractList,ArrayList,LinkedList,Vector
类关系:List>AbstractList>(ArrayList,LinkedList,Vector)
AbstractList
List接口的抽象实现类,它提供了List接口的一些基本实现。
ArrayList
最常用的List接口实现类,底层使用可变长度的动态数组实现
。ArrayList有一个初始容量(capacity = 10),当元素数量大于初始容量时进行扩容,新的数组长度 = 旧数组长度 + 旧数组长度 / 2。索引查询元素的速度非常快。如果在中间插入元素时,由于后面的元素全部要后移一位,所以性能会比较差。因此,它比较时候查询修改,而不适合增删,由于没有做并发访问控制,所以它是一个非线程安全的集合。允许重复元素或null元素。
LinkedList
List接口的双向链接的实现类,底层链表实现
,允许NULL元素。内存中是无序保存。它插入的速度会很快,但是查询一个元素的速度较ArrayList速度慢很多。是一个非线程安全的集合。
Vector
Vector底层使用动态数组实现
,默认初始容量为10,可以通过构造方法指定初始容量,同时可以指定扩容时的增量。它的关键方法都加了synchronized,所以是一个线程安全的集合。
set常见类及其区别
set存储特点:相对无序存储
,不可以存储相同的元素(排重
),不能通过下标访问**
set常见类:HashSet, LinkedHashSet,TreeSet
HashSet
HashSet实现了HashMap键的维护,且存取速度比较快。
存储特点:相对无序存储,排重,通过哈希表实现的集合
hashSet特点:
- Set中是不能出现重复数据的。
- Set中可以出现空数据。
- Set中的数据是无序的。
排重的原理:在创建一个HashSet集合往里面添加元素时,该集合会自动调用该元素的hashCode()方法,自动比较集合内是否有相同的哈希码,如果哈希码相同,集合会自动调用该类的equals()方法,如果equals()判断相等了才确定该元素是重复元素,它会将新添加的元素覆盖掉之前相同的元素。在使用基本类型包装器的时候,hashCode()和equals()已经被重写好了,不用再自己重写。
LinkedHashSet
LinkedHashSet类是具有可预知迭代顺序的Set接口的哈希表和链接列表实现。是HashSet的子类。
存储特点:相对有序存储,排重,通过链表实现的集合
LinkedHashSet特点:性能比HashSet好,但是插入时性能稍微逊色于HashSet。
排重的原理:与hashSet相同
TreeSet
TreeSet是TreeMap的键的维护
TreeSet特点:
- 不能写入空数据
- 写入的数据是有序的。
- 不写入重复数据
Map常见类及其区别
HashMap
- HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。
- HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。
- HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。
HashTable
- Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。
- Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。
- Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
HashMap与HashTable的区别
1. 继承的父类不同
2. 线程安全性不同
3. 是否提供contains方法
4. key和value是否允许null值
5. 两个遍历方式的内部实现上不同
6. hash值不同
7. 内部实现使用的数组初始化和扩容方式不同
附加:迭代器迭代
这里主要是迭代arraylist和map来分析
arraylist迭代代码:
List<String> list = new ArrayList<String>();
list.add("lichee");
list.add("yang");
// 使用 foreach 遍历 list
for (String str:list){
System.out.println(str);
}
// 使用迭代器进行相关的遍历
ListIterator<String> ite = list.listIterator();
while (ite.hasNext()){
System.out.println(ite.next());
}
map迭代代码:
Map<String,String> map = new HashMap<>();
map.put("1","lichee");
map.put("2","yang");
System.out.println("通过 map.values() 获得 value,但是不能获得 key");
for (String val : map.values()){
System.out.println(val);
}
System.out.println("通过 map.keyset() 遍历得到 key 和value");
for (String key : map.keySet()){
System.out.println("key = " + key + " ; value ="+ map.get(key));
}
System.out.println("通过 map.entrySet() 遍历得到 key 和 value,容量大时适用");
for (Map.Entry<String,String> mapentry : map.entrySet()){
System.out.println(mapentry);
}
System.out.println("通过 map.entrySet() 使用 iterator 遍历 key 和 value");
Iterator<Map.Entry<String , String>> it = map.entrySet().iterator();
while (it.hasNext()){
Map.Entry<String , String> entry = it.next();
System.out.println("key = " + entry.getKey() + " ; value ="+ entry.getValue());
}