【总结】java集合
一.collection
1、List接口和Set接口都继承自Collection接口,Collection接口继承Iterable接口(Iterable有一个Iterator方法),即可迭代的;Collection只能存储引用类型(对于基本数据类型进行装箱操作)
2、List接口存储元素特点:有序(存进去什么顺序取出来还什么顺序),可重复;Set接口存储元素特点:无序,不可重复
3、实现List接口主要的类包括ArrayList,LinkedList,Vector;实现Set的主要类包括:hashSet,TreeSet(自动排序)
1.List
1.ArrayList
(1)基本情况
ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量(capacity),表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。Java泛型只是编译器提供的语法糖,所以这里的数组是一个Object数组,以便能够容纳任何类型的对象。
(2)扩容机制
ArrayList是采取延迟分配对象空间的
①不指定ArrayList的初始容量,在第一次add的时候会把容量初始化为10个,这个数值是确定的;
②ArrayList的扩容时机为add的时候容量不足,扩容的后的大小为原来的1.5倍,扩容需要拷贝以前数组的所有元素到新数组
(2)特点
查询效率高,插入删除效率低。查找的话,直接通过下标可以查找到,所以效率快;插入删除的话,由于插入(删除)位置后面的元素都需要移动,所以效率较差。
2.LinkedList
(1)基本情况
LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack)。这样看来,LinkedList简直就是个全能冠军。当你需要使用栈或者队列时,可以考虑使用LinkedList,一方面是因为Java官方已经声明不建议使用Stack类,更遗憾的是,Java里根本没有一个叫做Queue的类(它是个接口名字)
(2)栈和队列的选择
关于栈或队列,现在的首选是ArrayDeque(双端队列),它有着比LinkedList(当作栈或队列使用时)有着更好的性能。
A、ArrayDeque内部使用数组实现,并且是循环数组
B、LinkedList内部使用链表实现
(3)特点
LinkedList底层通过双向链表实现。增删快,查找慢(增删只需要改变前后指针指向,查找需要从链表头开始查找)。为追求效率LinkedList没有实现同步(synchronized),如果需要多个线程并发访问,可以先采用Collections.synchronizedList()方法对其进行包装。
3.Vector
(1)和ArrayList一样,底层使用数组实现
(2)vector是线程安全的,效率受到影响。
(3)vector在多线程环境下也会受到线程安全问题。比如说,一个线程去删除i位置上的元素,另外一个线程去拿i位置上的元素,就会报异常。
(4)默认长度:10 扩容为原来的2倍(arraylist是1.5倍)
4.Stack
Stack是继承自Vector的,所以用法啊,线程安全什么的跟Vector都差不多,只是有几个地方需要注意:
(1)add()和push(),stack是将最后一个element作为栈顶的,所以这两个方法对stack而言是没什么区别的,但是,它们的返回值不一样,add()返回boolean,就是添加成功了没有;push()返回的是你添加的元素。为了可读性以及将它跟栈有一丢丢联系,推荐使用push。
(2)peek()和pop(),这两个方法都能得到栈顶元素,区别是peek()只是读取,对原栈没有什么影响;pop(),从字面上就能理解,出栈,所以原栈的栈顶元素就没了。
2.Set
HashSet添加的元素是存放在HashMap的key位置上,而value取了默认常量PRESENT,是一个空对象。(为什么不用null?因为set的remove返回Boolean,如果value设为null,remove后为null,并不代表它删除成功)
1.HashSet
(1)不能保证元素的排列顺序,顺序有可能发生变化
(2)不是同步的
(3)集合元素可以是null,但只能放入一个null
2.TreeSet
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
(1)TreeSet 是二叉树实现的,TreeSet中的数据是自动排好序的,不允许放入null值。
(2)HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
(3)HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashCode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
2.Map
1.hashmap
(1)HashMap的结构:
HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。HashMap采用了链地址法,也就是数组+链表的方式处理hash冲突
将对向放入到HashMap或HashSet中时,有两个方法需要特别关心:A、hashCode()和equals()。hashCode()方法决定了对象会被放到哪个bucket里,当多个对象的哈希值冲突时,equals()方法决定了这些对象是否是“同一个对象”。所以,如果要将自定义的对象放入到HashMap或HashSet中,需要重写 hashCode()和equals()方法。
B、插入使用头插法
(2)两个重要的方法put() get()
①.put方法:调用key的hash方法得到这个元素在数组中的位置(即下标)如果该位置已经存在其它元素,那么在同一个位子上的元素将以链表的形式存放,通过equals方法依次比较链表中的key,相同则替换。不同则添加到表尾(1.8之前添加到表头)。
②.get方法:调用key的hash方法得到这个元素在数组中的位置(即下标),然后通过key的equals方法在对应位置的链表中找到需要的元素。
(需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn))
(3)为什么jdk8后插到链表尾?
HashMap在jdk1.7中采用头插入法,在扩容时会改变链表中元素原本的顺序,以至于在并发场景下导致链表成环的问题。而在jdk1.8中采用尾插入法,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了
(4)HashMap的resize(rehash)
当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的。所以为了提高查询的效率,就要对HashMap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,这是一个常用的操作,而在HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。
那么HashMap什么时候进行扩容呢?当HashMap中的元素个数超过数组大小loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过160.75=12的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
(5)HashMap的性能参数
HashMap():构建一个初始容量为 16,负载因子为 0.75 HashMap。扩容为原来的2倍
(6)Fail-Fast机制
java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。
这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。
在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map (注意到modCount声明为volatile,保证线程之间修改的可见性)
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() + " and value= " + entry.getValue());
}
2.LinkedHashMap
(1)基本信息
HashMap有一个问题,迭代hashmap并不是有序的。所以出现了LinkedHashMap,它集成了Hashmap,是有序的
(2)实现原理
它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表
3.TreeMap
TreeMap集合是基于红黑树(Red-Black tree)的 NavigableMap实现。该集合最重要的特点就是可排序,该映射根据其键的自然顺序进行排序
4.HashMap和Hashtable对比
(1)Hashtable基于Dictionary类,Hashmap基于AbstractMap类
(2)HashMap不是线程安全的;HashTable是线程安全的,其线程安全是通过Sychronized实现。由于上述原因,HashMap效率高于HashTable
5.hashmap为什么不是线程安全?
HashMap的get操作可能因为resize而引起死循环(cpu100%)
6.concurrenthashmap?
Hashtable容器使用synchronized来保证线程安全,这样每一时刻只能有一条线程访问集合,效率非常低
jdk1.7 concurrenthashmap采用分段锁,将数据分成一段一段存储,每一段数据使用一把锁(segment分段锁)存储。所以修改某一数据时只需要获得该段的segement锁,其它段的数据仍然能正常的读写
JDK1.8的实现已经摒弃了Segment的概念,而是直接用数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本
【总结】java集合的更多相关文章
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- Scala集合和Java集合对应转换关系
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 用Scala编码的时候,经常会遇到scala集合和Java集合互相转换的case,特意mark一 ...
- java集合你了解多少?
用了java集合这么久,还没有系统的研究过java的集合结构,今天亲自画了下类图,总算有所收获. 一.所有集合都实现了Iterable接口. Iterable接口中包含一个抽象方法:Iterator& ...
- 深入java集合学习1-集合框架浅析
前言 集合是一种数据结构,在编程中是非常重要的.好的程序就是好的数据结构+好的算法.java中为我们实现了曾经在大学学过的数据结构与算法中提到的一些数据结构.如顺序表,链表,栈和堆等.Java 集合框 ...
- Java集合框架List,Map,Set等全面介绍
Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I] +--java.util.ArrayList [C] +- ...
- Java集合框架练习-计算表达式的值
最近在看<算法>这本书,正好看到一个计算表达式的问题,于是就打算写一下,也正好熟悉一下Java集合框架的使用,大致测试了一下,没啥问题. import java.util.*; /* * ...
- 【集合框架】Java集合框架综述
一.前言 现笔者打算做关于Java集合框架的教程,具体是打算分析Java源码,因为平时在写程序的过程中用Java集合特别频繁,但是对于里面一些具体的原理还没有进行很好的梳理,所以拟从源码的角度去熟悉梳 ...
- Java 集合框架
Java集合框架大致可以分为五个部分:List列表,Set集合.Map映射.迭代器.工具类 List 接口通常表示一个列表(数组.队列.链表 栈),其中的元素 可以重复 的是:ArrayList 和L ...
- Java集合概述
容器,是用来装东西的,在Java里,东西就是对象,而装对象并不是把真正的对象放进去,而是指保存对象的引用.要注意对象的引用和对象的关系,下面的例子说明了对象和对象引用的关系. String str = ...
- 深入java集合系列文章
搞懂java的相关集合实现原理,对技术上有很大的提高,网上有一系列文章对java中的集合做了深入的分析, 先转载记录下 深入Java集合学习系列 Java 集合系列目录(Category) HashM ...
随机推荐
- 神经网络全连接层+softmax:
如下图:(图片来自StackExchange) 强化说明全连接层: 1.通常将网络最后一个全连接层的输入,即上面的x \mathrm{x}x,视为网络从输入数据提取到的特征. 2. 强化说明softm ...
- 20190531模拟赛总结&反思
T1: 来源:Codeforces - Classroom Watch Describe: 给出一个正整数 n,现在问存在多少个 x,使得 x在十进制下的每一位之和加上 x 等于 n. Solut ...
- 智慧组织(SO)如何敏捷构建?
人类社会正处于千年未有之变局的关键时刻--互联网.大数据.AI和实体经济深度融合,数据正在重新定义世界并重构财富体系."新旧交织.破立并存",数字经济方兴未艾,传统势力逐步淡出.各 ...
- leetcode1558题解【贪心】
leetcode1558.得到目标数组的最少函数调用次数 题目链接 算法 贪心 时间复杂度O(nlogN),N为数组中最大的那个数. 1.题意就是给定一个函数,该函数有两种功能,一种就是将数组中的所有 ...
- Java基础——HashMap
1.HashMap底层的实现 JDK 1.7 中 HashMap 是以数组+链表的形式组成的 JDK 1.8 之后数组+链表/红黑树的组成的,当链表大于 8 并且容量大于 64 时,链表结构会转换成红 ...
- 普利姆算法(prim)
普利姆算法(prim)求最小生成树(MST)过程详解 (原网址) 1 2 3 4 5 6 7 分步阅读 生活中最小生成树的应用十分广泛,比如:要连通n个城市需要n-1条边线路,那么怎么样建设才能使工程 ...
- Lyndon Word相关
Lyndon Word 定义 对于字符串 \(S\),若 \(S\) 的最小后缀为其本身,那么称 \(S\) 为 \(\text{Lyndon}\) 串(\(\text{Lyndon Word}\)) ...
- 源码安装IVRE
简介:IVRE(又名DRUNK)是一款开源的网络侦查框架工具,IVRE使用Nmap.Zmap进行主动网络探测.使用Bro.P0f等进行网络流量被动分析,探测结果存入数据库中,方便数据的查询.分类汇总统 ...
- Charles 模拟弱网
1.Charles安装方法: 1)在官网下载安装: 2)输入如下注册码破解,Charles 4.2.7 目前版本,可用. Registered Name: https://zhile.io ...
- javascript 原型与原型链浅析
原型 和原型链 什么是原型链 简单理解就是原型组成的链,对象的__proto__它的是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过_ ...