重拾Java第五篇-集合
- 集合,数据的容器,每天都用,来来来,复习一下
为什么要用集合,数组不可以吗
- 数组存储数据没错可以,但是数组一旦指定了长度就不能超过,当数据未知个数时,就有点麻烦啦~
集合和数组有什么不一样吗?
- 数组的元素的数据类型,即可以是基本数据类型,也可以是对象。而集合则只能是对象,所以需要存储基本数据类型时,就要存储他们的包装类,例如要存储int类型,对应的包装类为Integer类型。
集合的分类
Collection集合体系.png Map集合体系.png-
集合根接口
- Collection
- Map,键值对,具有映射关系的数据
-
根接口的子接口,其中Map没有子接口,而直接是实现。
- Collection
- List,有序,可重复
- Set,无序,不可重复
- Collection
-
List接口的常用实现类
- ArrayList,底层为数组实现
- LinkedList,底层为双向联表实现
- Vector,可以理解为线程安全的的ArrayList,ArrayList是线程不安全的
- CopyOnWriteArrayList,JDK1.5-concurrent包中增加的针对并发而设计的List接口实现类
-
Set接口的常用实现类
- HashSet,底层为哈希表,无序,不可重复,如重复,新值会覆盖旧值
- LinkedHashSet,底层为链表实现的哈希表,有序,不可重复
- TreeSet,底层为红黑树,整体记录会按指定规则排序
- CopyOnWriteArraySet,和CopyOnWriteArrayList类似,但实现的是Set接口。
-
Map接口的常用实现类
- HashMap,底层为哈希表,键值对。无序,最多只允许一条记录的key值为Null(多条会覆盖),允许多条记录的Value为Null,非同步的。
- LinkedHashMap,底层为链表实现的哈希表。键值对,有序。
- TreeMap,底层为红黑树,键值对,整体记录会按指定规则排序
- Hashtable,和HashMap类似,不同的是,Key和Value均不可为Null,并且他是线程安全的,所以性能会比较低。
- ConcurrentHashMap,应对并发设计的Map实现。
List集合实现类的异同
-
ArrayList,底层为数组实现,所以存储空间是连续的,做查询时会比较快。但是做插入、删除时,每次都需要挪动数组元素,所以会比较慢。
-
LinkedList,底层为双向链表,链表元素之间头尾相接,做插入时只要找到前面的元素,再将当前元素接上尾部,再找后面的元素,接上头部即可,所以插入、删除速度会比较快。而查询时,内存地址不一定是连续的,所以查找会比较慢。
-
Vector,可以理解为线程安全的的ArrayList,他的增删查改都加了synchronized关键字保证线程安全,但是损耗了性能,现在一般不使用它,而使用Collections工具类调用synchronizedList进行包装(实质也是用了装饰者模式将增删改查方法加上synchronized关键字保证线程安全)。
-
CopyOnWriteArrayList,针对并发而设计的List接口实现类,多用于读多写少的场景,顾名思义就是在写的操作的时候,copy一份数据到新的容器,再将引用指向新的容器引用,整个过程是加锁实现线程安全的,而读是不加锁的。
-
总结
-
单线程 读的操作比较多,一般使用ArrayList,增删操作比较多使用LinkedList。
-
多线程,Collections工具类调用synchronizedList包装List实现,Vector不推荐使用了。
-
高并发场景,CopyOnWriteArrayList读写分离解决并发问题。
-
Set集合实现类的异同
-
HashSet,底层为哈希表,无序,不能存储重复元素,如重复,新值会覆盖旧值,哈希表生成索引,速度比较快。不关心顺序,需要排除重复时使用。
-
LinkedHashSet,底层为链表实现的哈希表,有序,不可重复,当需要不重复,并且有序的场景时使用。
-
TreeSet,底层为红黑树,可以插入后,进行排序,当需要插入后,不是按插入顺序排序,而是需要一定规则排序时使用,例如数字大小,字母A、B顺序。
-
总结
-
单线程
-
不关心顺序,只需要保证不重复,使用HashSet
-
需要保证插入时的顺序排序,使用LinkedHashSet
-
需要全部插入后,整体排序是按指定顺序排序时,使用TreeSet
-
-
多线程
- 当需要保证线程安全时,使用Collections工具类调用synchronizedMap包装Map实现。
-
高并发
- 可以使用CopyOnWriteArraySet进行并发处理
-
Map集合实现类的异同
-
HashMap,底层为哈希表,键值对。无序,最多只允许一条记录的key值为Null(多条会覆盖),允许多条记录的Value为Null,非同步的。
-
LinkedHashMap,底层为链表实现的哈希表,键值对,有序,key和value均允许为空,非同步的
-
TreeMap,底层为红黑树,键值对,整体记录会按指定规则排序
-
Hashtable,和HashMap类似,不同的是,Key和Value均不可为Null,并且他是线程安全的,所以性能会比较低。
-
ConcurrentHashMap,应对并发设计的Map实现,实现了锁分离,对Hash桶分为18段,在get操作是不加锁,set方式按段加锁
-
总结
-
单线程
-
不关心顺序,只需要保证不重复,使用HashMap
-
需要保证插入时的顺序排序,使用LinkedHashMap
-
需要全部插入后,整体排序是按指定顺序排序时,使用TreeMap
-
-
多线程
- 当需要保证线程安全时,使用Collections工具类调用synchronizedMap包装Map实现。
-
高并发
- 可以使用ConcurrentHashMap进行并发处理
-
常用集合操作API
-
boolean add(Object o);
向集合中插入数据,如果集合对象被添加操作改变了返回true。就是说插入成功了。ArrayList<String> list = new ArrayList<>(); list.add("Wally");
-
boolean addAll(Collection
c);,将另外一个集合c的所有元素添加到指定集合,操作成功了返回true。ArrayList<String> list = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); list2.add("Barry"); list.addAll(list2);
-
void clear();清空集合元素,集合长度为0。
ArrayList<String> list = new ArrayList<>(); list.add("Barry"); list.clear();
-
boolean contains(Object o),判断集合是否包含了指定元素。
ArrayList<String> list = new ArrayList<>(); String name = "Barry"; list.add(name); list.contains(name);
-
boolean containsAll(Collection c),判断集合是否包含了指定集合c中的所有元素。
ArrayList<String> list = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); String name = "Barry"; list.add(name); list2.add(name); list2.add("Wally"); list2.containsAll(list);
-
boolean isEmpty(),判断集合是否为空,长度为0返回true,否则返回false。
ArrayList<String> list = new ArrayList<>(); list.isEmpty();
-
boolean remove(Object
o),从集合中移除指定元素,如果集合中有多个元素匹配,只会删除第一个匹配的元素。操作成功返回true,否则为false。ArrayList<String> list = new ArrayList<>(); String name = "Barry"; list.add(name); list.remove(name);
-
boolean removeAll(Collection c),从集合中移除指定集合c中所有的元素。
ArrayList<String> list = new ArrayList<>(); String name = "Barry"; //[Barry] list.add(name); ArrayList<String> list2 = new ArrayList<>(); list2.add(name); //[Barry, wally] list2.add("Wally"); //移除后[Wally] list2.removeAll(list);
-
boolean retainAll(Collection
c),从集合中移除指定集合c中不包含的元素。相当于只保留了2个集合的交集部分。ArrayList<String> list = new ArrayList<>(); String name = "Barry"; //[Barry] list.add(name); ArrayList<String> list2 = new ArrayList<>(); list2.add(name); //[Barry, wally] list2.add("Wally"); //只保留2个集合的交集部分,就只有[Barry] list2.retainAll(list);
特殊集合才有的API
- ArrayList
- 按角标进行查找元素
ArrayList<String> list = new ArrayList<>();
list.add("Barry");
//Barry
String result = list.get(0);
- 按角标删除元素
ArrayList<String> list = new ArrayList<>();
list.add("Barry");
list.remove(0);
- 角标遍历
ArrayList<String> list = new ArrayList<>();
list.add("Barry");
list.add("Wally");
list.add("Lucy");
for (int i = 0; i < list.size(); i++) {
String element = list.get(i);
System.out.println("element " + element);
}
Map集合API
- 增加元素
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
map.putAll(map2);
- 移除元素
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
map.remove("Barry");
- 获取所有的Key集合
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
Set<String> keySet = map.keySet();
- 获取所有Value的集合
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
Collection<Integer> values = map.values();
- 判断某个Key是否在集合中
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
boolean isContains = map.containsKey("Barry");
- 判断某个Value是否存在于集合中
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
boolean isContainsValue = map.containsValue(18);
- 遍历
HashMap<String, Integer> map2 = new HashMap<>();
map.put("Barry", 22);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
}
网友评论