经常使用集合类简介及线程安全和非线程安全的集合对象

简介

Java中集合类有不少,只介绍经常使用的集合类:html

     

 线程安全和非线程安全的集合对象

1、概念:java

  • 线程安全:就是当多线程访问时,采用了加锁的机制;即当一个线程访问该类的某个数据时,会对这个数据进行保护,其余线程不能对其访问,直到该线程读取完以后,其余线程才可使用。防止出现数据不一致或者数据被污染的状况。
  • 线程不安全:就是不提供数据访问时的数据保护,多个线程可以同时操做某个数据,从而出现数据不一致或者数据污染的状况。
  • 对于线程不安全的问题,通常会使用synchronized关键字加锁同步控制。
  • 线程安全工做原理: jvm中有一个main memory对象,每个线程也有本身的working memory,一个线程对于一个变量variable进行操做的时候, 都须要在本身的working memory里建立一个copy,操做完以后再写入main memory。 当多个线程操做同一个变量variable,就可能出现不可预知的结果。
    而用synchronized的关键是创建一个监控monitor,这个monitor能够是要修改的变量,也能够是其余本身认为合适的对象(方法),而后经过给这个monitor加锁来实现线程安全,每一个线程在得到这个锁以后,要执行完加载load到working memory 到 use && 指派assign 到 存储store 再到 main memory的过程。才会释放它获得的锁。这样就实现了所谓的线程安全。

2、线程安全(Thread-safe)的集合对象:算法

  • Vector 线程安全:
  • HashTable 线程安全:
  • StringBuffer 线程安全:

3、非线程安全的集合对象:api

  • ArrayList :
  • LinkedList:
  • HashMap:
  • HashSet:
  • TreeMap:
  • TreeSet:
  • StringBulider:

4、相关集合对象比较:数组

Vector、ArrayList、LinkedList:
一、Vector:
     Vector与ArrayList同样,也是经过数组实现的,不一样的是它支持线程的同步,即某一时刻只有一个线程可以写Vector,避免多线程同时写而引发的不一致性,但实现同步须要很高的花费,所以,访问它比访问ArrayList慢。
二、ArrayList:
  a. 当操做是在一列数据的后面添加数据而不是在前面或者中间,并须要随机地访问其中的元素时,使用ArrayList性能比较好。
  b. ArrayList是最经常使用的List实现类,内部是经过数组实现的,它容许对元素进行快速随机访问。数组的缺点是每一个元素之间不能有间隔,当数组大小不知足时须要增长存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,须要对数组进行复制、移动、代价比较高。所以,它适合随机查找和遍历,不适合插入和删除。
三、LinkedList:
  a. 当对一列数据的前面或者中间执行添加或者删除操做时,而且按照顺序访问其中的元素时,要使用LinkedList。
  b. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操做表头和表尾元素,能够看成堆栈、队列和双向队列使用。安全

Vector和ArrayList在使用上很是类似,均可以用来表示一组数量可变的对象应用的集合,而且能够随机的访问其中的元素。数据结构

ArryList和LinkedList的区别:多线程

 

Vector与ArrayList比较:jvm

 1. 性能上
ide

  ArrayList底层数据结构是数组,适合随机查找和遍历,不适合插入和删除,线程不安全,效率高。。LinkedList底层数据结构是链表, 适合数据的动态插入和删除,随机访问和遍历速度比较慢,线程不安全,效率高。。

 

  2. 同步性

 

    Vectors是可同步的,是线程安全的。ArrayList是不可同步的,不是线程安全的。因此, 通常单线程推荐用ArrayList,多线程中则用Vector 

 

 3. 数据增加

 

    往一个ArrayList或者Vector里插入一个元素时,若是内部数组空间不够,ArrayList或Vector会扩展它的大小。 Vector在默认状况下增加一倍的大小,而ArrayList增长50%的大小。

 

 

HashTable、HashMap、HashSet:
     HashTable和HashMap采用的存储机制是同样的,不一样的是:
一、HashMap:
a. 采用数组方式存储key-value构成的Entry对象,无容量限制;
b. 基于key hash查找Entry对象存放到数组的位置,对于hash冲突采用链表的方式去解决;
c. 在插入元素时,可能会扩大数组的容量,在扩大容量时需要从新计算hash,并复制对象到新的数组中;
d. 是非线程安全的;
e. 遍历使用的是Iterator迭代器;

二、HashTable:
a. 是线程安全的;
b. 不管是key仍是value都不容许有null值的存在;在HashTable中调用Put方法时,若是key为null,直接抛出NullPointerException异常;
c. 遍历使用的是Enumeration列举;

三、HashSet:
a. 基于HashMap实现,无容量限制;
b. 是非线程安全的;
c. 不保证数据的有序

 

 

 

TreeSet、TreeMap:
    TreeSet和TreeMap都是彻底基于Map来实现的,而且都不支持get(index)来获取指定位置的元素,须要遍从来获取。另外,TreeSet还提供了一些排序方面的支持,例如传入Comparator实现、descendingSet以及descendingIterator等。
一、TreeSet:
a. 基于TreeMap实现的,支持排序;
b. 是非线程安全的;

二、TreeMap:
a. 典型的基于红黑树的Map实现,所以它要求必定要有key比较的方法,要么传入Comparator比较器实现,要么key对象实现Comparator接口;
b. 是非线程安全的;

 

Collection有两个子接口:List和Set,两者主要区别在于:list数据有序存放、可重复;set中数据无序存放,不可重复。

Vector

  Vector类实现了一个动态数组,主要用在事先不知道数组的大小,以及须要频繁地进行查找,插入,删除工做,或者只是须要一个能够改变大小的数组的状况。

建立:

Vector类支持4种构造方法。

第一种构造方法建立一个默认的向量,默认大小为10:

Vector()

第二种构造方法建立指定大小的向量。

Vector(int size)

第三种构造方法建立指定大小的向量,而且增量用incr指定. 增量表示向量每次增长的元素数目(当该vector对象添加的元素接近原先分配的内存极限时,会以incr大小自动扩大该对象拥有的内存容量,以容纳更多的数据)

Vector(int size,int incr)

第四中构造方法建立一个包含集合c元素的向量:利用父类对象建立子类对象

Vector(Collection c) 

  经常使用的vector操做方法:增、删、查、改。

增:

vec.add(E element) 
将指定元素追加到此向量的末尾。 
vec.add(int index, E element) 
在此向量的指定位置插入指定的元素。 
vec.addAll(Collection c) 
将指定 Collection 中的全部元素按顺序追加到此向量的末尾。 
vec.addAll(int index, Collection c) 
在指定位置将指定 Collection 中的全部元素插入到此向量中。

删:

vec.remove(int index) 
移除此向量中指定位置的元素。 
vec.remove(value v) 
移除向量中元素值为v的元素。
vec.removeAll(Collection c) 
今后向量中移除包含在集合c 中的全部元素。 
vec.removeAllElements() 
今后向量中移除所有组件,并将其大小设置为零。 
vec.removeRange(int fromIndex, int toIndex) 
移除位于 fromIndex(包括)与 toIndex(不包括)之间的全部元素。

vec.clear() 移除全部元素。

查:

vec.get(int index)

返回向量中指定位置的元素。 
vex.indexOf(value v) 
返回v值在vec中的下标。
vec.isEmpty() 
检查该向量是否为空。 
vec.lastElement() 
返回此向量的最后一个元素。

int capacity() 
返回此向量的当前容量。

int size() 
返回此向量中的组件数。

String toString() 
返回此向量的字符串表示形式,其中包含每一个元素的 String 表示形式。 
改:

vec.set(int index, E element) 
用指定的元素替换此向量中指定位置处的元素。 
vex.setElementAt(E obj, int index) 
将此向量指定 index 处的组件设置为指定的对象。 
vec.setSize(int newSize) 
设置此向量的大小。

ArrayList

ArrayList就是动态的数组,能够动态的增长和减小元素,灵活的设置数组的大小。基本与Vector同样。

建立:

 ArrayList提供了三个构造器:

public ArrayList(); 
默认的构造器,将会以默认(16)的大小来初始化内部的数组 
public ArrayList(Collection c); 
用一个集合对象来构造,并将该集合的元素添加到ArrayList 
public ArrayList(int n); 
用指定n的大小来初始化内部的数组.

增:

方法摘要
 boolean add(E e)
          将指定的元素添加到此列表的尾部。
 void add(int index, E element)
          将指定的元素插入此列表中的指定位置。
 boolean addAll(Collection<? extends E> c)
          按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的全部元素添加到此列表的尾部。
 boolean addAll(int index, Collection<? extends E> c)
          从指定的位置开始,将指定 collection 中的全部元素插入到此列表中。

删:

 E remove(int index)
          移除此列表中指定位置上的元素。
 boolean remove(Object o)
          移除此列表中首次出现的指定元素(若是存在)。
protected  void removeRange(int fromIndex, int toIndex)
          移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的全部元素。
void clear()
          移除此列表中的全部元素。

 

查: 

 E get(int index)
          返回此列表中指定位置上的元素。
 int indexOf(Object o)
          返回此列表中首次出现的指定元素的索引,或若是此列表不包含元素,则返回 -1。
 boolean isEmpty()
          若是此列表中没有元素,则返回 true
int size()
          返回此列表中的元素数。
boolean contains(Object o)
          若是此列表中包含指定的元素,则返回 true

ArrayList支持3种遍历方式

第一种,经过迭代器遍历

Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

 第二种,随机访问,经过索引值去遍历。

Integer value = null;for (int i=0; i<list.size(); i++) {
    value = (Integer)list.get(i);        
}

第三种,for-each遍历

Integer value = null;
for (Integer integ:list) {
    value = integ;
}

改:

 E set(int index, E element)
          用指定的元素替代此列表中指定位置上的元素。

 

 Object[] toArray()
   

HashMap

这里咱们先讲hashmap,具体缘由等讲到hashset的时候就知道了。

  HashMap基于哈希表的 Map 接口实现,以key-value的形式存在。在HashMap中,系统 key-value 当成一个总体进行处理,系统老是根据 Hash 算法来计算 key-value 的存储位置,这样能够保证能快速存、取 Map 的 key-value 对。系统调用key的 hashCode() 方法获得其 hashCode 值——每一个 Java 对象都有 hashCode() 方法,均可经过该方法得到它的 hashCode 值。获得这个对象的 hashCode 值以后,系统会根据该 hashCode 值来决定key—value的存储位置。
建立
构造方法摘要
HashMap() 
          构造一个具备默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap
HashMap(int initialCapacity) 
          构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap
HashMap(int initialCapacity, float loadFactor) 
          构造一个带指定初始容量和加载因子的空 HashMap
HashMap(Map<? extends K,? extends V> m) 
          构造一个映射关系与指定 Map 相同的 HashMap
 容量表示哈希表中桶的数量,初始容量是建立哈希表时的容量,加载因子是哈希表在其容量自动增长以前能够达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。
增:
V put(K key, V value) 
       插入键值对。
 void putAll(Map<? extends K,? extends V> m) 
          把map中的键值对插入到hashmap中。
删:
 V remove(Object key) 
          若是此映射中存在该键的映射关系,则将其删除。
 void

clear() 
          今后映射中移除全部映射关系。

 查:

 V get(Object key) 
          返回指定键在此标识哈希映射中所映射的值,若是对于此键来讲,映射不包含任何映射关系,则返回 null

 

boolean isEmpty() 
          若是此映射不包含键-值映射关系,则返回 true
 Set<K> keySet() 
          返回此映射中所包含的键的 set 。//获取hashmap中的key集合。
Collection<V> values() 
          返回此映射所包含的值的 collection 视图。

 

 int size() 
          返回此映射中的键-值映射关系数。

 

 boolean containsKey(Object key) 
          若是此映射包含对于指定的键的映射关系,则返回 true
 boolean containsValue(Object value) 
          若是此映射将一个或多个键映射到指定值,则返回 true

HashSet

  HashSet是基于 HashMap 实现的,底层采用 HashMap 来保存数据。全部放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个静态的 Object 对象(向上转型,这样value就能够是各类基本类型的值了)。HashSet 的绝大部分方法都是经过调用 HashMap 的方法来实现的,所以 HashSet 和 HashMap 两个集合在实现本质上是相同的。 
建立:
HashSet hashSet = new HashSet();
HashSet hashset=new HashSet(collection);
增:
hashset.add(value);//向集合中添加一个元素
hashset.add(array[]);//把数组中的值添加到集合中
删:

删除一个元素:hashSet.remove(Object);

删除全部元素:hashSet.clear();

查:

用迭代器遍历:

Iterator it = hashSet.iterator();
  while(it.hasNext()){
   Object obj = it.next();

   而后针对obj进行一系列的操做,好比:输出值、若是obj是类对象则调用属性、方法。

}
 boolean contains(Object o)
          若是此 set 包含指定元素,则返回 true
 boolean isEmpty()
          若是此 set 不包含任何元素,则返回 true
 int size()
          返回此 set 中的元素的数量(set 的容量)。

 当从HashSet中访问元素时,HashSet先计算该元素的hashCode值(也就是调用该对象的hashCode())方法的返回值),而后直接到该hashCode对应的位置去取出该元素。  为了保证HashSet能正常工做,要求当两个对象用equals比较相等时,hashCode也要相等,不然就会有可能加入两个相同的项。

HashSet的特色:

(1)HashSet不是同步的,多个线程访问是须要经过代码保证同步

(2)集合元素值能够为null。

相关文章
相关标签/搜索