Java集合体系总结
一、集合框架
集合是容纳数据的容器,java常用的集合体系图如下。以集合中是否运行重复元素来分,主要有List和Set接口,List集合中可以有重复元素,Set集合集合中的元素不可重复,Iterator和List Iterator是遍历集合的2个迭代器,Map是存储Key/Value键值对的容器。
java集合体系图
二、迭代器
迭代器的用法写在后面,这里说明Iterator和ListIterator的区别:
- Iterator在遍历一个集合的过程中不能修改集合中的对象,ListIterator可以修改对象
- ListIterator从后往前遍历,有hasPrevious()方法,Iterator没有
- ListIterator可以在遍历过程中进行添加元素操作,Iterator不能,否则会报
java.util.ConcurrentModificationException异常。
三、List集合
List集合存储不唯一、有序的对象,可以操作角标。
3.1 ArrayList
3.1.1内部实现
ArrayList也叫变长数组,数组的长度是固定的,ArrayList可以随着元素的增多长度增加,内部实现为数组。ArrayList在添加元素时首先会判断长度,长度不够时,长度扩展到原来到1.5倍,原数组复制到新数组。
3.1.2关键属性
| 属性 | 取值或结论 |
|---|---|
| 是否允许重复 | 允许 |
| 是否有序 | 有序 |
| 是否允许为空 | 允许 |
| 是否线程安全 | 否 |
| 使用场景 | 多查询、少增删 |
3.1.3 测试示例
创建一个ArrayList对象,添加5个元素,其中一个为null:
arrayList.add("a1");
arrayList.add("a2");
arrayList.add(null);
arrayList.add("a3");
arrayList.add("a4");
System.out.println(arrayList);
打印结果:
[a1, a2, null, a3, a4]
使用迭代器for循环方式遍历:
for (Iterator iter=arrayList.iterator();iter.hasNext();){
System.out.println(iter.next());
}
使用迭代器while循环方式遍历:
Iterator iter=arrayList.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
}
存储自定义对象:
public class Boy {
private String name;
private int age;
//省略setter、getter、构造器和toString()方法
}
添加Boy对象到ArrayList中并打印:
ArrayList<Boy> boys=new ArrayList<>();
Boy b1=new Boy("Tom",12);
Boy b2=new Boy("Jack",11);
Boy b3=new Boy("Mike",15);
boys.add(b1);
boys.add(b2);
boys.add(b3);
System.out.println(boys);
Iterator<Boy> iter=boys.iterator();
while (iter.hasNext()){
Boy b=iter.next();
System.out.println(b.getName()+"----"+b.getAge());
}
结果:
[Boy{name='Tom', age=12}, Boy{name='Jack', age=11}, Boy{name='Mike', age=15}]
Tom----12
Jack----11
Mike----15
3.1.4 转成线程安全
非线程安全的ArrayList
ArrayList<String> arrayList = new ArrayList();
线程安全的ArrayList
List arrayList =Collections.synchronizedList(new ArrayList<String>()) ;
3.1.5 常用方法
- clear():移除列表中的所有元素
- contains(Object o): 包含指定元素
- get(int index):返回列表中指定位置上的元素
- indexOf(Object o): 返回列表中首次出现指定元素的索引,如果列表不包含,则返回-1
- isEmpty():列表为空返回true
- lastIndexOf(Object o):返回列表中最后一次出现指定元素的索引,如果列表不包含元素则返回-1
- remove(int index):移除列表中指定位置的元素
- remove(Object o):移除列表中首次出现的指定元素
- removeRange(int fromIndex,int toIndex):移除列表中索引在fromIndex(包括)和toIndex(不包括)之间的所有元素。
- size():返回集合的元素个数
- set(int index,E element):修改指定位置上的元素
- toArray():按顺序返回包含此列表中所有元素的数组
3.2 LinkedList
3.2.1内部实现
内部实现为双向链表,删除和增加速度快,查找速度慢。
3.2.2关键属性
| 属性 | 取值或结论 |
|---|---|
| 是否允许重复 | 允许 |
| 是否有序 | 有序 |
| 是否允许为空 | 允许 |
| 是否线程安全 | 否 |
| 使用场景 | 多增删、少查询 |
3.2.3 测试示例
LinkedList当作FIFO的队列使用,也就是常用的add方法添加元素:
LinkedList quene=new LinkedList();
quene.add("a");
quene.add("b");
quene.add("c");
quene.add("d");
System.out.println("打印队列:"+quene);
System.out.println("获取队头:"+quene.getFirst());
System.out.println("获取队尾:"+quene.getLast());
System.out.println("移除队头:"+quene.pop());
System.out.println("移除队头之后的队列:"+quene);
打印结果:
打印队列:[a, b, c, d]
获取队头:a
获取队尾:d
移除队头:a
移除队头之后的队列:[b, c, d]
LinkedList当作FILO的栈使用:
LinkedList stack = new LinkedList();
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
System.out.println("打印栈:"+stack);
System.out.println("获取栈顶元素:"+stack.peek());
System.out.println("打印栈:"+stack);
System.out.println("取出栈顶元素:"+stack.pop());
System.out.println("打印栈:"+stack);
打印结果:
打印栈:[4, 3, 2, 1]
获取栈顶元素:4
打印栈:[4, 3, 2, 1]
取出栈顶元素:4
打印栈:[3, 2, 1]
除了ArrayList中包含的基本方法以为,LinkedList中多了getFirst()、getLast()、addFirst()、addLast()、peek()、peekFirst()、peekLast()、removeFirst()、removeLast()等方法。
3.2.4 转成线程安全
List<Integer> linkedList=Collections.synchronizedList(new LinkedList<Integer>());
3.3 Vector
Vector内部是数组结构,线程安全,速度较慢,几乎不用。
四、Set集合
Set集合中的元素唯一、无序,没有角标。
4.1HashSet
4.1.1内部实现
内部结构是哈希表,对象存入HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,确保set中没有存储相同的对象。判断两个元素是否相同,首先通过hashCode()方法判断的是2个元素的哈希值是否相同,再根据equals()方法判断值是否相同,只有2者都相同才是统一元素。
4.1.2 基本属性
| 属性 | 取值或结论 |
|---|---|
| 是否允许重复 | 不允许 |
| 是否有序 | 无序 |
| 是否允许为空 | 允许(只有一个null) |
| 是否线程安全 | 否 |
| 使用场景 | 对象不重复和需要快速查找的场景 |
4.1.3 测试示例
HashSet<String> hashSet=new HashSet();
hashSet.add("abc");
hashSet.add("张三");
hashSet.add("李四");
hashSet.add("tim");
hashSet.add(null);
hashSet.add(null);
System.out.println("HashSet 大小:"+hashSet.size());
Iterator iter=hashSet.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
}
打印结果:
HashSet 大小:5
null
李四
张三
abc
tim
添加自定义对象,仍然添加Boy类中的对象
Boy b1=new Boy("神乐",12);
Boy b2=new Boy("神乐",12);
HashSet<Boy> boys=new HashSet<>();
boys.add(b1);
boys.add(b2);
System.out.println(boys);
结果:
[Boy{name='神乐', age=12}, Boy{name='神乐', age=12}]
这时候b1和b2其实是一个对象,在Boy类中重写hashCode()和equals()方法:
public class Boy {
private String name;
private int age;
//省略setter、getter、构造器和toString()方法
@Override
public int hashCode() {
return name.hashCode()+age;
}
@Override
public boolean equals(Object obj) {
if (this==obj) return true;
if (!(obj instanceof Boy)) throw new ClassCastException("类型错误");
Boy boy=(Boy) obj;
return this.name.equals(boy.name)&&(this.age==boy.age);
}
}
重写equals和hashCode方法以后,上述集合中就会只添加一个对象:
[Boy{name='神乐', age=12}]
4.1.4 转成线程安全
Set<String> hSet=Collections.synchronizedSet(new HashSet<String>());
4.1.5 唯一且有序
LinkedHashSet集合中都元素唯一且有序,这里都有序是指添加顺序。
LinkedHashSet<String> lHashSet= new LinkedHashSet<String>();
lHashSet.add("abc");
lHashSet.add("张三");
lHashSet.add("李四");
lHashSet.add("tim");
lHashSet.add(null);
iter=lHashSet.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
}
打印结果:
abc
张三
李四
tim
null
4.2 TreeSet
4.2.1 内部实现
TreeSet内部实现为二叉树,可以对元素进行排序
4.2.2 基本属性
| 属性 | 取值或结论 |
|---|---|
| 是否允许重复 | 不允许 |
| 是否有序 | 无序 |
| 是否允许为空 | 允许(只有一个null) |
| 是否线程安全 | 否 |
| 使用场景 | 去重且排序 |
4.2.3 测试示例
Boy b1=new Boy("定春",16);
Boy b2=new Boy("神乐",12);
Boy b3=new Boy("桑巴",13);
TreeSet<Boy> treeSet=new TreeSet<>(new Comparator<Boy>() {
@Override
public int compare(Boy o1, Boy o2) {
return o1.getAge()-o2.getAge();
}
});
treeSet.add(b1);
treeSet.add(b2);
treeSet.add(b3);
System.out.println(treeSet);
打印结果:
[Boy{name='神乐', age=12}, Boy{name='桑巴', age=13}, Boy{name='定春', age=16}]
4.2.4 转成线程安全
TreeSet<Boy> treeSet=new TreeSet<>(new Comparator<Boy>() {
@Override
public int compare(Boy o1, Boy o2) {
return o1.getAge()-o2.getAge();
}
});
Set<Boy> treeSet1=Collections.synchronizedSet(treeSet);
五、Map集合
Map只存储的是键值对,Key必须唯一且不为空,key允许为null。
5.1HashMap
5.1.1基本属性
| 属性 | 取值或结论 |
|---|---|
| 是否允许重复 | key重复会被覆盖,value可重复 |
| 是否有序 | 无序 |
| 是否允许为空 | key和value都允许为空 |
| 是否线程安全 | 否 |
5.1.2 测试示例
词频统计:
String[] arr={"Hadoop","Lucene","ES","ES","ES","Hadoop","Java","JS"};
//TreeMap<String,Integer> map=new TreeMap<>();
HashMap<String,Integer> map=new HashMap<>();
for (String str:arr){
if (map.containsKey(str)){
map.put(str,map.get(str)+1);
}else{
map.put(str,1);
}
}
Set<String> keys=map.keySet();
Iterator<String> iter=keys.iterator();
while (iter.hasNext()){
String str=iter.next();
System.out.println(str+"---"+map.get(str));
}
打印结果:
Java---1
Hadoop---2
JS---1
Lucene---1
ES---3
如果想按value排序,可以改成TreeMap();
六、性能对比
ArrayList遍历性能对比
ArrayList的遍历可以用一般for循环、foreach循环、Iterator迭代器三种方式实现,为了测试它们的性能,先创建一个ArrayList对象,添加5万个字符串:
ArrayList<String > a = new ArrayList();
for (int i = 0; i < 60000; i++) {
a.add(""+i);
}
for 循环打印并记录耗时:
long start = System.currentTimeMillis();
for (int i = 0; i < a.size(); i++) {
System.out.print(a.get(i));
}
long end = System.currentTimeMillis();
System.out.println("\n下标for循环:" + (end - start));
结果:
150
foreach循环打印并记录耗时:
start = System.currentTimeMillis();
for (String i : a) {
System.out.print(i);
}
end = System.currentTimeMillis();
System.out.println("\nforeach:" + (end - start));
耗时:
95
Iterator循环打印:
start=System.currentTimeMillis();
Iterator iter=a.iterator();
while (iter.hasNext()){
System.out.print(iter.next());
}
end=System.currentTimeMillis();
System.out.println("\nIter:"+(end-start));
耗时:
60
结论:一般for 循环最慢、foreach次之、Iterator最快。
另外,Iterator遍历还有另外一种变形方式,效率和while形式一样。
for(Iterator it=a.iterator();it.hasNext();){
System.out.print(it.next());
}
七、参考文章
有些文章总结的很好,列出来供参考学习:
Java集合框架
Java集合体系总结的更多相关文章
- JAVA集合体系之-开篇
JAVA的集合体系是个庞大的知识体系,里面涵盖了,如数组结构,链表,红黑树,排序算法,线程安全等等知识点,接下来将会使用一系列的分享文章整理自己的学习心得,留的温故而知新.下图是整理出来的JAVA集合 ...
- 一目了然了解JAVA集合体系
在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量.一旦在数组初始化时指定了这个数组长度,这个数组长度就是不可变的,如果 ...
- 根据jdk1.8源码整理而得,java集合体系(继承、实现关系)图解,超清晰,一看就懂,方便记忆
一.前言 1. 该关系图是本人根据JDK1.8 源码整理所得,只整理了常用的.常见的集合,并非全部. 2. 整理逻辑: Collection接口下有两个子接口:List 和 Set 接口. Map是独 ...
- java集合体系
Collection接口: 1.单列集合类的根接口. 2.定义了可用于操作List.Set的方法--增删改查: 3.继承自Iterable<E>接口,该接口中提供了iterator() 方 ...
- 浅谈Java集合体系及底层实现原理
集合加载因子 https://blog.csdn.net/qq_34627002/article/details/79769261 底层原理: https://blog.csdn.net/qq_258 ...
- Java.数据结构.集合体系详解
I. 第一部分:常见数据结构 首先简单说下数据结构. 什么是数据结构?数据结构就是组织数据的方式. 常见的数据结构:栈,堆,树,图,数组,队列,链表. 这里主要介绍与java集合体系相关的栈.数组和链 ...
- 1.Java集合总结系列:Java集合概述
一.概述 集合是 Java 中非常重要的 API,在实际应用中非常广泛,在许多面试中也是必考的知识点. Java 所有集合类都位于 java.util 包下,Java 的集合只能保存对象,而无法保存保 ...
- java集合体系结构总结
好,首先我们根据这张集合体系图来慢慢分析.大到顶层接口,小到具体实现类. 首先,我想说为什么要用集合?简单的说:数组长度固定,且是同种数据类型.不能满足需求.所以我们引入集合(容器)来存储任意数据类型 ...
- Java集合--阻塞队列及各种实现的解析
阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...
随机推荐
- 20145310 GDB调试汇编堆栈分析
GDB调试汇编堆栈分析 由于老师说要逐条分析汇编代码,所以我学习卢肖明同学的方法,重新写了一篇博客. 代码: #include<stdio.h> short addend1 = 1; st ...
- COGS 197 [HAOI2008] 排名系统
★★★☆ 输入文件:rank.in 输出文件:rank.out 简单对比 时间限制:1 s 内存限制:128 MB [题目描述] 排名系统通常要应付三种请求:上传一条新的得分记录.查询 ...
- JAVA基础补漏--泛型通配符
泛型通配符只能用于方法的参数 不能用对象定义 public class Test { public static void main(String[] args) { ArrayList<Str ...
- Windows Server 2008驱动安装全攻略
安装设备驱动程序原本是一件非常简单的事情,很多驱动程序在安装的时候我们只要不停单击“下一步”按钮,就能让驱动程序顺利地在对应计算机系统“落户”;不过,当身边的计算机系统升级为Windows Serve ...
- MQ的前世今生
1983年孟买26岁的工程师Vivek Ranadive设想一种软件总线,同年Teknekron诞生了. 最初用于高盛,用于解决金融交易.于是发布订阅的MQ The Information B ...
- Redis windows主从服务配置
一.下载redis解压 如图: 二.复制redis.windows.conf 文件为 redis.windows_6380.conf 三.修改配置IP和端口 四.配置从属于主服务的IP 和 端口 五. ...
- 爬虫框架Scrapy之CrawlSpiders
CrawlSpiders 通过下面的命令可以快速创建 CrawlSpider模板 的代码: scrapy genspider -t crawl tencent tencent.com 上一个案例中,我 ...
- java.lang.IllegalArgumentException的解决方法
java.lang.IllegalArgumentException这个错误基本上就是jdk版本的问题 把jdk1.8换成jdk1.7就可以了 这里可以设置jdk最低版本 这里默认要选择jdk1.7 ...
- 解题报告:hdu1013 Digital Roots
2017-09-07 22:02:01 writer:pprp 简单的水题,但是需要对最初的部分进行处理,防止溢出 /* @theme: hdu 1013 Digital roots @writer: ...
- C# Memcached 缓存
之前做的功能,程序可能有不足之处,但还是要记录下 ICacheStrategy.cs文件 public interface ICacheStrategy { /// <summary> / ...