Java中的容器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Java中的容器
1、Java的容器类有两种基本类型:Collection和Map,区别在于容器中每个位置保存的元素个数。
Collection每个位置只能保存一个元素,Map保存的是键值对。
2、迭代器,是一个对象,它的工作是遍历并选择序列中的对象,“轻量级”的对象,创建它的代价小。
常用方法:next();hasNext();
3、Collection:
(1)List:
ArrayList:允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢,可以理解为容量大小可变的数组。
LinkedList:向List中间插入与移除的开销并不大,随机访问则相对较慢,可以当作堆栈、队列和双向队列使用。
最佳做法是将ArrayList作为默认首选,只有当程序性能因为经常从表中间进行插入和删除变差时,才选择LinkedList。
(2)Set,不保存重复的元素:
HashSet:为快速查找而设计的Set,存入HashSet的对象必须定义hashCode()。
TreeSet:保持次序的Set,底层为树结构,使用它可以从Set中提取有序的序列,“按对象比较函数对元素排序”,而不是指“元素插入的次序”。
LinkedHashSet:具有HashSet的查询速度,并且内部使用链表维护元素的顺序(插入的次序),于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
HashSet性能总是比TreeSet好。
TreeSet存在的唯一原因是它可以维持元素的排序状态。
4、Map:
(1)HashMap:基于散列表的实现。
插入和查询“键值对”的开销是固定的。
(2)LinkedHashMap:类似于HashMap,但是迭代器遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)次序。
比HashMap慢一点,但是迭代访问时会更快。
(3)TreeMap:基于红黑树的实现。
查看“键”或“键值对”时,它们会被排序(次序由Comparable或Comparator决定),所得到的结果是经过排序的,而且是唯一带有subMap()方法的Map,可以返回一个子树。
首选HashMap,只有在需要一个总是排好序的Map时,才使用TreeMap。
5、如果要使用散列的数据结构(HashSet,HashMap,LinkedHashSet或者LinkedHashMap)最好先覆盖hashCode()和equals(),因为从Object继承下来的hashCode()方法默认是使用对象的地址计算散列值
学习笔记:java中HashCode
为什么HashCode对于对象是如此的重要?
一个对象的HashCode就是一个简单的Hash算法的实现,虽然它和那些真正的复杂的Hash
算法相比还不能叫真正的算法,它如何实现它,不仅仅是程序员的编程水平问题,而是关系到你的对象在存取是性能的非常重要的关系.有可能,不同的HashCode可能会使你的对象存取产生,成百上千倍的性能差别。
我们先来看一下,在JAVA中两个重要的数据结构:HashMap和Hashtable,虽然它们有很大的区别,如继承关系不同,对的约束条件(是否允许null)不同,以及线程安全性等有着特定的区别,但从实现原理上来说,它们是一致的.所以,我们只以Hashtable来说明:
在java中,存取数据的性能,一般来说当然是首推数组,但是在数据量稍大的容器选择中,Hashtable将有比数组性能更高的查询速度.具体原因看下面的内容。
Hashtable在存储数据时,一般先将作为key的对象的HashCode和0x7FFFFFFF做与操作,因为一个对象的HashCode可以为负数,这样操作后可以保证它为一个正整数.然后以Hashtable 的长度取模,得到值对象在Hashtable中的索引。
index = (o.hashCode() & 0x7FFFFFFF)%hs.length;这个值对象就会直接放在Hashtable 的第index位置,对于写入,这和数组一样,把一个对象放在其中的第index位置,但如果是查询,经过同样的算法,Hashtable可以直接通过key得到index,从第index取得这个值对象,而数组却要做循环比较.所以对于数据量稍大时,Hashtable的查询比数据具有更高的性能。
虽然不同对象有不同的hashcode,但不同的hashCode经过与长度的取余,就很可能产生相同的index。
极端情况下会有大量的对象产生一个相同的索引.这就是关系Hashtable性能问题的最重要的问题:
Hash冲突。
常见的Hash冲突是不同key对象最终产生了相同的索引,而一种非常甚至绝对少见的Hash
冲突是,如果一组对象的个数大过了int范围,而HashCode的长度只能在int范围中,所以肯定要有同一组的元素有相同的HashCode,这样无论如何他们都会有相同的索引.当然这种极端的情况是极少见的,可以暂不考虑,但是对于同的HashCode经过取模,则会产中相同的索引,或者不同的对象却具有相同的HashCode,当然具有相同的索引。
事实上一个设计各好的HashTable,一般来说会比较平均地分布每个元素,因为Hashtable的长度总是比实际元素的个数按一定比例进行自增(装填因子一般为0.75)左右,这样大多数的索引位置只有一个对象,而很少的位置会有几个元素.所以Hashtable中的每个位置存放的是一个链表,对于只有一个对象是位置,链表只有一个首节点(Entry),Entry的next为null.然后有hashCode,key,属性保存了该位置的对象的HashCode,key和(对象本身),如果有相同索引的对象进来则会进入链表的下一个节点.如果同一个索引中有多个对象,根据HashCode和key可以在该链表中找到一个和查询的key相匹配的对象。
从上面我看可以看到,对于HashMap和Hashtable的存取性能有重大影响的首先是应该使该数据结构中的元素尽量大可能具有不同的HashCode,虽然这并不能保证不同的HashCode产生不同的index,但相同的HashCode一定产生相同的index,从而影响产生Hash冲突。
对于一个象,如果具有很多属性,把所有属性都参与散列,显然是一种笨拙的设计.因为对象的HashCode()方法几乎无所不在地被自动调用,如equals比较,如果太多的对象参与了散列.那么需要的操作常数时间将会增加很大.所以,挑选哪些属性参与散列绝对是一个编程水平的问题。
从实现来说,一般的HashCode方法会这样:
return Attribute1.HashCode() + Attribute1.HashCode()..[+super.HashCode()]。
我们知道,每次调用这个方法,都要重新对方法内的参与散列的对象重新计算一次它们的HashCode的运算,如果一个对象的属性没有改变,仍然要每次都进行计算,所以如果设置一个标记来缓存当前的散列码,只要当参与散列的对象改变时才重新计算,否则调用缓存的hashCode,这可以从很大程度上提高性能。
默认的实现是将对象内部地址转化为整数作为HashCode,这当然能保证每个对象具有不同的HasCode,因为不同的对象内部地址肯定不同(废话),但java语言并不能让程序员获取对象内部地址,所以,让每个对象产生不同的HashCode有着很多可研究的技术。
如果从多个属性中采样出能具有平均分布的hashCode的属性,这是一个性能和多样性相矛盾的地方,如果所有属性都参与散列,当然hashCode的多样性将大大提高,但牺牲了性能,而如果只能少量的属性采样散列,极端情况会产生大量的散列冲突,如对"人"的属性中,如果用性别而不是姓名或出生日期,那将只有两个或几个可选的hashcode值,将产生一半以上的散列冲突.所以如果可能的条件下,专门产生一个序列用来生成HashCode将是一个好的选择(当然产生序列的性能要比所有属性参与散列的性能高的情况下才行,否则还不如直接用所有属性散列)。
如何对HashCode的性能和多样性求得一个平衡,可以参考相关算法设计的书,其实并不一定要求非常的优秀,只要能尽最大可能减少散列值的聚集.重要的是我们应该记得HashCode对于我们的程序性能有着生要的影响,在程序设计时应该时时加以注意
容器类可以大大提高编程效率和编程能力,在Java2中,所有的容器都由SUN公司的Joshua Bloch进行了重新设计,丰富了容器类库的功能。
Java2容器类类库的用途是“保存对象”,它分为两类:
Collection----一组独立的元素,通常这些元素都服从某种规则。
List必须保持元素特定的顺序,而Set不能有重复元素。
Map----一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。
另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。
1.迭代器
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。
迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。
第一次调用Iterator的next()方法时,它返回序列的第一个元素。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个
方向遍历List,也可以从List中插入和删除元素。
2.List的功能方法
List(interface): 次序是List最重要的特点;它确保维护元素特定的顺序。
List为Collection添加了许多方法,使得能够向List中间插入与移除元素(只推荐LinkedList使用)。
一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素。
ArrayList: 由数组实现的List。
它允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。
ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。
LinkedList: 对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。
它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。
3.Set的功能方法
Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。
加入Set的Object 必须定义equals()方法以确保对象的唯一性。
Set与Collection有完全一样的接口。
Set接口不保证维护元素的次序。
HashSet: 为快速查找而设计的Set。
存入HashSet的对象必须定义hashCode()。
TreeSet: 保持次序的Set,底层为树结构。
使用它可以从Set中提取有序的序列。
LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。
于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。
需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。
查看文章
Java容器类List、ArrayList、Vector及m ap、HashTable、HashMap分别的区别2007年04月16日星期一15:15Java容器类List、ArrayList、Vector及m ap、HashTable、HashMap 分别的区别2007-03-06 17:06一、List与ArrayList的区别
List->AbstractList->ArrayList
(1) List是一个接口,ArrayList是一个实现了List接口的具体类。
他们是父子关系,我们常用的是ArrayList,但常用List的引用去操作ArrayList
这是一个简单的面向接口编程的一种,如:List m yList = new ArrayList();
(2)他们主要是用来保存对象的集合,记得是保存对象的哦,你可别传个int(类)进去啊
(3)要取出它里面保存的对象可以用下标,如:Object aaa = m yList.get(0);
这样我们就把保存在m yList里的第一个对象取出来给了aaa 啦。
二、祥解
---------------------------1楼------------------------------------
好像List和Map都是接口
不能实例化的
以前这么写List list = new Vector();
现在这么写List list = new ArrayList();
用ArrayList 代替了Vector 因为前者的性能比后者好;
但是两个都是实现了List借口的
同理Map m ap = new HashTable();(以前)
Map m ap = new HashMap();(现在)
-------------------------------2楼-------------------------------
ArrayList和HashMap是异步的,Vector和HashTable是同步的,所以Vector和HashTable 是线程安全的,而ArrayList和HashMap并不是线程安全的。
因为同步需要花费机器时间,所以Vector和HashTable的执行效率要低于ArrayList和HashMap。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│└Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。
用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
ArrayList类
ArrayList实现了可变大小的数组。
它允许所有元素,包括null。
ArrayList没有同步。
size,isEm pty,get,set方法运行时间为常数。
但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。
其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capaci ty),即用于存储元素的数组的大小。
这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。
当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。
一个Map中不能包含相同的key,每个key只能映射一个value。
Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。
,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。
因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
----------------------------------3楼------------------------------------------
1.
List是接口,List特性就是有序,会确保以一定的顺序保存元素.
ArrayList是它的实现类,是一个用数组实现的List.
Map是接口,Map特性就是根据一个对象查找对象.
HashMap是它的实现类,HashMap用hash表实现的Map,就是利用对象的hashcode(hashcode()是Object的方法)进行快速散列查找.(关于散列查找,可以参看<<数据结构>>)
2.
一般情况下,如果没有必要,推荐代码只同List,Map接口打交道.
比如:List list = new ArrayList();
这样做的原因是list就相当于是一个泛型的实现,如果想改变list的类型,只需要:
List list = new LinkedList();//LinkedList也是List的实现类,也是ArrayList的兄弟类
这样,就不需要修改其它代码,这就是接口编程的优雅之处.
另外的例子就是,在类的方法中,如下声明:
private void doMyAction(List list){}
这样这个方法能处理所有实现了List接口的类,一定程度上实现了泛型函数.
3.
如果开发的时候觉得ArrayList,HashMap的性能不能满足你的需要,可以通过实现List,Map(或者Collection)来定制你的自定义类.
可以参考The Art Of Com puter Programm ing的Sorting and Searching部分
Java容器类List、ArrayList、V ector及map、HashTable、HashMap的区别(zh)2008-01-18 14:51List和Map是接口,ArrayList和HashMap分别是它们的实现类.
ArrayList和HashMap是异步的,V ector和HashTable是同步的,所以V ector和HashTable 是线程安全的,而ArrayList和HashMap并不是线程安全的。
因为同步需要花费机器时间,所以V ector和HashTable的执行效率要低于ArrayList和HashMap。
Collection
├List 接口
│├LinkedList 链表
│├ArrayList 顺序结构动态数组类
│└V ector 向量
│└Stack 栈
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。
用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,V ector和Stack。
ArrayList类
ArrayList实现了可变大小的数组。
它允许所有元素,包括null。
ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。
但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。
其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。
这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。
当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。
一个Map中不能包含相同的key,每个key只能映射一个value。
Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value 和null key。
,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap 的容量成比例。
因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
比较分析V ector、ArrayList和hashtable hashmap数据结构2007-07-19 11:38线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。
这些类均在java.util包中。
本文试图通过简单的描述,向读者阐述各
个类的作用以及如何正确使用这些类。
Collection
├List
│├LinkedList
│├ArrayList
│└V ector
│└Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
Collection接口
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。
一些Collection允许相同的元素而另一些不行。
一些能排序而另一些不行。
Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。
后一个构造函数允许用户复制一个Collection。
如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。
典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一个元素
}
由Collection接口派生的两个接口是List和Set。
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。
用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java 的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,V ector和Stack。
LinkedList类
LinkedList实现了List接口,允许null元素。
此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。
这些操作使LinkedList可被用作堆栈(stack),队列
(queue)或双向队列(deque)。
注意LinkedList没有同步方法。
如果多个线程同时访问一个List,则必须自己实现访问同步。
一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList类
ArrayList实现了可变大小的数组。
它允许所有元素,包括null。
ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。
但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。
其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。
这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。
当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
V ector类
V ector非常类似ArrayList,但是V ector是同步的。
由V ector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为V ector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了V ector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
Stack 类
Stack继承自V ector,实现一个后进先出的堆栈。
Stack提供5个额外的方法使得V ector 得以被当作堆栈使用。
基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。
Stack刚创建后是空栈。
Set接口
Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。
很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object)。
如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。
Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。
一个Map中不能包含相同的key,每个key只能映射一个value。
Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
Hashtable类
Hashtable继承Map接口,实现一个key-value映射的哈希表。
任何非空(non-null)的对象都可作为key或者value。
添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
Hashtable通过initial capacity和load factor两个参数调整性能。
通常缺省的load factor 0.75较好地实现了时间和空间的均衡。
增大load factor可以节省空间但相应的查找时间将增大,
这会影响像get和put这样的操作。
使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一个数,比如2,用相应的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ”+ n);
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。
hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode 方法,而不要只写其中一个。
Hashtable是同步的。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。
,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。
因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
WeakHashMap类
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
总结
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。
这就是针对抽象编程。
同步性
V ector是同步的。
这个类中的一些方法保证了V ector中的对象是线程安全的。
而ArrayList 则是异步的,因此ArrayList中的对象并不是线程安全的。
因为同步的要求会影响执行的效
率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。
数据增长
从内部实现机制来讲ArrayList和V ector都是使用数组(Array)来控制集合中的对象。
当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,V ector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。
所以如果你要在集合中保存大量的数据那么使用V ector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
使用模式
在ArrayList和V ector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用O(1)表示。
但是,如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置。
为什么会这样呢?以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。
这一切意味着什么呢?
这意味着,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用V ector 或ArrayList都可以。
如果是其他操作,你最好选择其他的集合操作类。
比如,LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的?O(1),但它在索引一个元素的使用缺比较慢-O(i),其中i是索引的位置.使用ArrayList也很容易,因为你可以简单的使用索引来代替创建iterator对象的操作。
LinkList也会为每个插入的元素创建对象,所有你要明白它也会带来额外的开销。
最后,在《Practical Java》一书中Peter Haggar建议使用一个简单的数组(Array)来代替V ector 或ArrayList。
尤其是对于执行效率要求高的程序更应如此。
因为使用数组(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。
V ector和Hashtable都是jdk1.0的就有了的。
后来到java2后,java的容器框架改动很多,为了兼容,就让V ector和Hashtable分别实现了新的容器框架的List和Map。
ArrayList和HashMap都是java2(也就是jdk1.2)后才有的。
1. 安全、效率方面:如果要实现同步安全,则要用V ector和Hashtable,否则则用ArrayList和HashMap,因为ArrayList和HashMap不考虑同步安全的问题,所以效率要高些。
但Collections类可以解决这个问题。
Collections.synchronizedList
Collections.synchronizedMap 2. 资源方面:当两者的容量已满时,它们都会自动增长其容量,但V ector是按其容量的一倍增长,而ArrayList则按其容量的50%增加,所以V ector 更能节省资源。
3.迭代器:V ector和Hashtable使用Enumeration,ArrayList和HashMap使用Iterator ARRAY是必须在声明的时候说明长度的; ARRYLIST也是和V ector类似,可以自动增加长度的。
List和Set的区别:List用来处理序列,而Set用来处理集。
List中的内容可以重复,而Set则不行。
V ector,ArrayList 和Hashtable,HashMap的区别: 1.V ector和ArrayList是数值联系对象。
按照插入的顺序进行排列,可以有重复值。
2.Hashtable和HashMap是对象联系对象。
按照自己的排列方式进行排序,不可以有重复值。
HashMap:继承了Map接口,实现用Keys来存储和访问V alues,Keys和V alues都可以为空,它与Hashtable类的区别在于Hashtable类的Keys不能为null, V ector内部实际是以Array实现的,也通过元素的整数索引来访问元素,但它只能存放ng.Object对象,不能用于存放基本类型数。