java容器类型_Java常见的容器类及其区别

版权声明:

一、分类:大类型主要分为以下两种类型

1)Collection:一个独立元素的序列,这些元素都服从一条或者多条规则。 List必须按照插入的顺序保存元素,而set不能有重复的元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

2)Map:一组成对的“键值对”对象,允许你使用键来查找值。

细分如下:

|Collection

|  ├List

|  │--├LinkedList

|  │--├ArrayList

|  │--└Vector

|  │     └Stack

|  ├Set

|  │--├HashSet

|  │--├TreeSet

|  │--└LinkedSet

|

|Map

├Hashtable

├HashMap

└WeakHashMap

917179495228

java-collection-hierarchy

二、具体区别

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。

917179495228

Collection主要方法

1、List接口

实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。

共同点:

LinkedList、ArrayList都实现了List接口,都是不同步的,线程不安全,元素是有序的、可重复。

1)LinkedList类

基于链表的数据结构,允许null元素,增加、删除、修改元素方面效率比ArrayList高。      此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

注意:LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:List list = Collections.synchronizedList(new LinkedList(…));

2) ArrayList类

基于数组的数据结构,不同步,线程不安全,查询(get set)效率高。

size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。

Array和ArrayList的区别及各自适用的场景

Array是数组,ArrayList是Array的加强版。

(1)array可以保存基本类型和对象类型,arrayList只能保存对象类型

(2)array数组的大小是固定的不能更改,而ArrayList的大小可以改变

(3)Array数组在存放的时候一定是同种类型的元素。ArrayList就不一定了,因为ArrayList可以存储Object。

(4)ArrayList有更加丰富的方法如addAll()、removeAll()、iterator()

适用场景:

如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,但是如果我们单纯只是想要以数组的形式保存数据,而不经常对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择ArrayList。如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用ArrayList就真的不是一个好的选择,因为它的效率很低,可以考虑选LinkedList。

3)Vector类

Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个 Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常。

4)Stack 类

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有 peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

2.Set接口

共同点:元素不重复

1)HashSet类

->不保证集合中元素的顺序

->允许包含值为null的元素,但最多只能有一个null元素。

2)TreeSet

TreeSet描述的是Set的一种变体——可以实现排序等功能的集合,它在将对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,并保证该集合元素组成的对象序列时刻按照“升序”排列。所以我们在使用TreeSet时候,里面装的元素一定是有序的,否则就不应该选择TreeSet。

3)LinkedSet

集合元素按插入顺序排列。

适用场景:

HashSet使用哈希表实现的,元素是无序的。添加、删除操作时间复杂度都是O(1)。TreeSet内部结构是一个树结构(红黑树),元素是有序的,添加、删除操作时间复杂度为O(log(n)),并且提供了first(), last(), headSet(), tailSet()等方法来处理有序集合。

LinkedHashSet是介于HashSet 和 TreeSet之间,内部是一个双向链表结构,所以它的插入是有序的,时间复杂度是O(1)。

简而言之,如何你需要的是一个快速的集合,建议你使用HashSet,如果你需要的是一个排序集合,请选择TreeSet,如果你需要一套能够存储插入顺序的集合,请使用LinkedHashSet。

3.Map集合接口

Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。

HashTable和HashMap区别

第一、继承不同。

public class Hashtable extends Dictionary implements Map

public class HashMap  extends AbstractMap implements Map

第二、Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

第三、Hashtable中,key和value都不允许出现null值。在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

第四、两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式。

第五、哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。

Hashtable计算hash值,直接用key的hashCode(),而HashMap重新计算了key的hash值,Hashtable在求hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用hash&0x7FFFFFFF后,再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值有可能为负数,而&0x7FFFFFFF后,只有符号外改变,而后面的位都不变。

第六,内部实现使用的数组初始化和扩容方式不同。

HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。

Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

前面分析了,Hashtable 的扩容方法是乘2再+1,不是简单的乘2,故hashtable保证了容量永远是奇数,结合之前分析hashmap的重算hash值的逻辑,就明白了,因为在数据分布在等差数据集合(如偶数)上时,如果公差与桶容量有公约数 n,则至少有(n-1)/n 数量的桶是利用不到的,故之前的hashmap 会在取模(使用位与运算代替)哈希前先做一次哈希运算,调整hash值。这里hashtable比较古老,直接使用了除留余数法,那么就需要设置容量起码不是偶数(除(近似)质数求余的分散效果好)。而JDK开发者选了11。

适用场景:

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

1、由于HashMap非线程安全,在只有一个线程访问的情况下,效率要高于HashTable

2、HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。

3、HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey。因为contains方法容易让人引起误解。

4、Hashtable继承自陈旧的Dictionary类,而HashMap是Java1.2引进的Map 的一个实现。

5、两者通过hash值散列到hash表的算法不一样,HashTbale是古老的除留余数法,直接使用hashcode,而后者是强制容量为2的幂,重新根据hashcode计算hash值,在使用hash 位与 (hash表长度 – 1),也等价取膜,但更加高效,取得的位置更加分散,偶数,奇数保证了都会分散到。前者就不能保证。

6、另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

fail-fast和iterator迭代器相关。如果某个集合对象创建了Iterator或者ListIterator,然后其它的线程试图“结构上”更改集合对象,将会抛出ConcurrentModificationException异常。但其它线程可以通过set方法更改集合对象是允许的,因为这并没有从“结构上”更改集合。但是假如已经从结构上进行了更改,再调用set方法,将会抛出IllegalArgumentException异常。

结构上的更改指的是删除或者插入一个元素,这样会影响到map的结构。

该条说白了就是在使用迭代器的过程中有其他线程在结构上修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

3)WeakHashMap类

WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值