Java中的集合包括三大类,它们是Set、List和Map,
它们都处于java.util包中,Set、List和Map都是接口,它们有各自的实现类。
List、Set都继承自Collection接口,Collection (所有集合类的接口)
  • Set(集) 实现类主要有HashSet和TreeSet
  • List(列表) 实现类主要有ArrayList,LinkedList,Vector
  • Map(映射)实现类主要有HashMap和TreeMap,HashTable
  • 线程安全类

  • 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:

    vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。

    statck:堆栈类,先进后出

    hashtable:就比hashmap多了个线程安全

    enumeration:枚举,相当于迭代器

  • StringBuffer也是线程安全的,(StringBuilder 不是线程安全的)

  • 除了这些之外,其他的都是非线程安全的类和接口。

    线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。

  • Collection 和 Map 的区别

    容器内每个为之所存储的元素个数不同。Collection类型者,每个位置只有一个元素。Map类型者,持有 key-value pair,像个小型数据库。

    List,Set都是继承自Collection接口,Map则不是

    (a) Collection
         --List:将以特定次序存储元素。所以取出来的顺序可能和放入顺序不同。
               --ArrayList / LinkedList / Vector
         --Set : 不能含有重复的元素
               --HashSet / TreeSet
     (b) Map
         --HashMap
         --HashTable
         --TreeMap

    总结
  • List,Set,Map将持有对象一律视为Object型别。

    Collection、List、Set、Map都是接口,不能实例化。    继承自它们的 ArrayList, Vector, HashTable, HashMap是具象class,这些才可被实例化。
    vector容器确切知道它所持有的对象隶属什么型别。vector不进行边界检查。

    1. 如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
    2. 如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
    3. 在除需要排序时使用TreeSet,TreeMap外,都应使用HashSet,HashMap,因为他们 的效率更高。
    4. 要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。 
    5. 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。一旦将对象置入容器内,便损失了该对象的型别信息。
    6. 尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

  • 7. set中不允许有重复的元素存在
  • 8. map的 key 集合和 set集合都不允许有重复的元素存在,list可以有重复的元素存在

    注意:
    1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
    2、Set和Collection拥有一模一样的接口。
    3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
    4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
    5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
          HashMap会利用对象的hashCode来快速找到key。
    6、Map中元素,可以将key序列、value序列单独抽取出来。
    使用keySet()抽取key序列,将map中的所有keys生成一个Set。
    使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。  

(2)List中的对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,如通过list.get(i)方式来获得List集合中的元素。
    (3)Set中的对象不按特定方式排序,并且没有重复对象。但它的有些实现类能对集合中的对象按特定方式排序,例如TreeSet类,它可以按照默认排序,也可以通过实现             java.util.Comparator<Type>接口来自定义排序方式。  
    (4) Map中的每一个元素包含一个键对象和值对象,它们成对出现。键对象不能重复,值对象可以重复。

关系如图:

或者:

Collections (操作集合的工具类)
对于集合类的操作不得不提到工具类Collections,它提供了许多方便的方法,如求两个集合的差集、并集、拷贝、排序等等。
由于大部分的集合接口实现类都是不同步的,可以使用Collections.synchronized*方法创建同步的集合类对象。
如创建一个同步的List:
List synList = Collections.synchronizedList(new ArrayList());
其实现原理就是重新封装new出来的对象,操作对象时用关键字synchronized同步。看源码很容易理解。
Collections部分源码:

static class SynchronizedCollection<e> implements Collection<e>, Serializable {

        final Collection<e> c;  // Backing Collection
final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection<e> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
mutex = this;
}
//...
public boolean add(E e) {
//操作集合时简单调用原本的ArrayList对象,只是做了同步
synchronized (mutex) {return c.add(e);}
}
//...

List(列表)

ArrayList、Vector是线性表,使用Object数组作为容器去存储数据的,添加了很多方法维护这个数组,使其容量可以动态增长,极大地提升了开发效率。它们明显的区别是ArrayList是非同步的,Vector是同步的。不用考虑多线程时应使用ArrayList来提升效率。

LinkedList是链表,略懂数据结构就知道其实现原理了。链表随机位置插入、删除数据时比线性表快,遍历比线性表慢。

由此可根据实际情况来选择使用ArrayList(非同步、非频繁删除时选择)、Vector(需同步时选择)、LinkedList(频繁在任意位置插入、删除时选择)。

Map(存储键值对,key唯一)

HashMap结构的实现原理是将put进来的key-value封装成一个Entry对象存储到一个Entry数组中,位置(数组下标)由key的哈希值与数组长度计算而来。如果数组当前下标已有值,则将数组当前下标的值指向新添加的Entry对象。

public class HashMap<k,v> extends AbstractMap<k,v> implements Map<k,v>, Cloneable, Serializable
{
transient Entry<k,v>[] table;
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
//遍历当前下标的Entry对象链,如果key已存在则替换
for (Entry<k,v> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
addEntry(hash, key, value, i);
return null;
}
}
static class Entry<k,v> implements Map.Entry<k,v> {
final K key;
V value;
Entry<k,v> next;
int hash;
}

TreeMap是由Entry对象为节点组成的一颗红黑树,put到TreeMap的数据默认按key的自然顺序排序,new TreeMap时传入Comparator自定义排序。红黑树网上很多资料,我讲不清,这里就不介绍了。

Set(保证容器内元素唯一性)

之所以先讲Map是因为Set结构其实就是维护一个Map来存储数据的,利用Map结构key值唯一性。 
HashSet部分源码:

public class HashSet<e>
extends AbstractSet<e>
implements Set<e>, Cloneable, java.io.Serializable
{ //无意义对象来作为Map的value
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
}

HashMap和HashTable的区别

具体的区别请参考:HashMap、HashTable、ConcurrentHashMap、HashSet区别 线程安全类

StringBuffer是线程安全,而StringBuilder是线程不安全的。对于安全与不安全没有深入的理解情况下,易造成这样的错觉,如果对于StringBuffer的操作均是线程安全的,然而,Java给你的保证的线程安全,是说它的方法是执行是排它的,而不是对这个对象本身的多次调用情况下,还是安全的。看看下边的例子,在StringBufferTest中有一个数据成员contents它是用来扩展的,它的每一次append是线程安全的,但众多次append的组合并不是线程安全的,这个输出结果不是太可控的,但如果对于log和getContest方法加关键字synchronized,那么结果就会变得非常条理,如果换成StringBuider甚至是append到一半,它也会让位于其它在此基础上操作的线程:

参考:Java基础之常用数据结构及原理分析

Java 常用数据结构对象的实现原理 集合类 List Set Map 哪些线程安全 (美团面试题目)的更多相关文章

  1. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  2. (6)Java数据结构-- 转:JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析  http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...

  3. 【转载】图解Java常用数据结构(一)

    图解Java常用数据结构(一)  作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...

  4. 动图+源码,演示Java中常用数据结构执行过程及原理

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

  5. 动图+源码,演示 Java 中常用数据结构执行过程及原理

    ​阅读本文大概需要 3.7 分钟. 作者:大道方圆 cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想 ...

  6. 图解Java常用数据结构(一)【转载】

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

  7. 图解Java常用数据结构(一)

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

  8. 图解Java常用数据结构

    最近在整理数据结构方面的知识, 系统化看了下 Java 中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于 jdk8, 可能会有些特性与 jdk7 之前不相同, 例如 LinkedList ...

  9. Java 常用数据结构深入分析(Vector、ArrayList、List、Map)

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

随机推荐

  1. JavaWeb学习日记----SAX解析XML

    1.SAX解析XML文档的方式: 与DOM方式解析不同,DOM方式解析是根据XML的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象.优点是可以很方便实现增删改操作.缺点是,如 ...

  2. 我从来不理解JavaScript闭包,直到有人这样向我解释它...

    摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...

  3. 坑:微信小程序wx.request和wx.uploadFile中传参数的区别

    微信小程序中通过组件<form>提交表单的时候,在js中通过e.detail.value得到所提交表单的json格式数据.一般提交表单我们都是通过wx.request请求,提交表单数据,通 ...

  4. finereport报表--动态格间运算 二

    报表输出

  5. 广州.NET微软技术俱乐部提技术问题的正确方式

    这是 北京.NET微软技术俱乐部 里一个人问问题的方式, 很赞, 所以希望大家问问题也采用这种方式. 耗时少, 使用12月8日活动上董志强先生介绍的windows 10 Snip&Sketch ...

  6. pthread_once()函数详解

    转自:pthread_once()函数详解 pthread_once()函数详解   在多线程环境中,有些事仅需要执行一次.通常当初始化应用程序时,可以比较容易地将其放在main函数中.但当你写一个库 ...

  7. 动态更新Icon

    动态更改图标主要用到activity-alias和PackageManager的setComponentEnabledSetting方法.具体步骤如下: 1.在AndroidManifest.xml中 ...

  8. 智能POS常见问题整理

    智能POS预警值为小于所设的数量,H5就会变为锁定状态 智能POS查看数据库方法: 商米D1:设置-存储设备和USB-内部存储设备-浏览-winboxcash tablet.db为智能POS数据库 W ...

  9. python模块shutil

    shutil.copyfileobj(fsrc, fdst,[ length]) 拷贝文件句柄,将类文件对象fsrc的内容复制到类文件对象fdst.如果给定整数长度,则为缓冲区大小.如果长度是负值意味 ...

  10. pycharm设置自动换行的方法

    只对当前文件有效的操作:菜单栏->View -> Active Editor -> Use Soft Wraps: 如果想对所有文件都有效,就要在setting里面进行操作:File ...