一.Java集合类概述
1.集合类:为了保存数量不确定的数据,以及具有映射关系的数据(关联数组)。集合类主要负责保存和盛装其他数据,因此集合类又叫做容器类。
2.集合类与数组的区别:
① 集合类中的数据数量不确定,而数组中数据的数量确定。
② 数组中的数据既可以是基本数据类型,又可以是对象。而集合类中只能保存对象。
3.Java集合框架的根接口:Collection和Map
Map保存的的每一项数据都是一个key-value对,其中key是不重复的。
二.Collection接口和Iterator接口
1.Collection接口
add,addAll,clear,contains,containAll,,remove,removeAll,size,isEmpty,toArray,iterator,re-tainAll等
2.Iterator接口
Iterator对象被称为迭代器,用于遍历集合中的元素。
三个方法:hasNext,next,remove
注意:
① 使用Iterator对集合元素进行迭代时,并不是把集合元素本身赋给迭代变量,而是把集合元素的值赋给迭代变量,所以修改迭代元素的值对于集合不会有任何影响。
② 使用Iterator对集合元素进行迭代时,集合元素不能被改变(Iterator的remove方法除外),否则会产生异常。
3.foreach循环
利用foreach循环也可以遍历集合中的元素。
与Iterator注意的两点相同。
三.Set接口
Set集合类似于一个罐子,其中的元素无序且不相等。Set集合判断两个元素是否相等是根据equal方法,而不是根据“==”来判断。
1.HashSet类
HashSet是根据哈希算法来存取集合中的元素。
HashSet集合判断两个元素相等的标准是:通过equals方法比较两个对象相等,并且hashCode方法的返回值也相等。
注意:
① 如果一个类重写equals方法,那么相应的也要重写hashCode方法。规则是:如果两个对象通过equals方法比较返回true,那么它们的hashCode方法的返回值也应该相同。
② 当向HashSet集合中添加可变对象时要格外注意,因为通过对可变对象的修改可能会导致HashSet集合中的两个元素完全相同,但是又处于不同的位置,从而导致HashSet集合无法准确的访问该对象。
LinkedHashSet类,是HashSet的子类,与HashSet类不同的是,它通过链表维持集合中元素的顺序,使得集合中的元素看起来时按照插入顺序保存的。
2.TreeSet类
继承了SortedSet接口,确保集合中的元素处于排序状态。
与HashSet类相比增加了如下几个方法:
first,last,lower,higher,subset,headSet,tailSet,comparator
TreeSet并不是按照元素的插入顺序进行排序,TreeSet支持两种排序算法:自然排序和定制排序。
·自然排序:TreeSet调用元素的compareTo方法来比较元素的大小关系,然后按照升序排列。如果试图将一个对象加入TreeSet集合,那么这个对象所对应的类必须实现Comparable接口,否则会抛出异常。向TreeSet集合中加入的必须是同一类型的对象,否则也会抛出异常。
TreeSet集合中两个对象完全相同的标准是:通过equals方法比较返回true,并且同compareTo方法比较返回0.
当向TreeSet中加入可变对象时要格外注意,对可变对象修改后,排序不会发生变化,删除元素也可能会失败,因为TreeSet中可能存在两个完全相同的元素。
总之,不要向HashSet和TreeSet中加入可变对象。
·定制排序:通过Comparator接口实现。加入TreeSet集合中的元素没有必要再实现Comparable接口,但是加入加入TreeSet集合中的元素仍然需要是同一类型。
3.EnumSet类
EnumSet是专为枚举类设计的集合类,EnumSet集合的元素必须为指定枚举类型的枚举值。
EnumSet没有暴露任何构造方法来构造该类的对象,要构造该类的对象必须通过EnumSet本身提供的静态方法。
主要的静态方法如下:
allOf,noneOf,of,range,copyof(EnumSet),copyOf(Collection),complementOf
如何选择实现Set接口的各个类:
·HashSet类的性能总是比TreeSet类的性能要好,而TreeSet类在需要排序时才使用。
·HashSet类的性能比LinkedHashSet类的性能也要略好一些,但是LinkedHashSet类在遍历集合元素时要快一些。
·EnumSet是所有的Set实现类中性能最好的,但是只能保存枚举类型的元素。
·Set实现类都不是线程安全的。
四.List接口
List是一个有序的集合,List集合中的每一个元素都有其对应的索引,所以List集合中的元素允许重复。List按照添加元素的先后顺序设置索引。
1.List接口与ListIterator接口
与Collection接口不同,List接口中增加一些根据索引操作元素的方法。
List接口中的方法:
·添加元素:add(Object),add(index,Object),addAll(Collection),addAll(index,Collection)
·删除元素:remove(Object),removeAll(Collection),remove(index)
·获取元素:get(index)
·替换元素:set(index,Object)
·截取元素:subList(fromIndex,toIndex)
·返回索引值:indexOf(Object),lastIndexOf(Object)
ListIterator接口是Iterator接口的子接口,它增加了一些新的方法,专门用来操作List集合。
ListIterator接口中新增加的方法有:
·hasPrevious()
·previous()
·add()
2.ArrayList和Vector实现类
ArrayList和Vector类都是基于数组实现的,所以ArrayList和Vector都封装了一个动态分配大小的数组Object[]。ArrayList和Vector类都有一个属性capacity,表示它们封装的数组Object[]的大小,capacity会随集合中元素的个数变化而自动变化。
ArrayList和Vector类可以通过以下方法来操作capacity属性:
·ensureCapacity(minCapacity)
·trimToSize()
Vector类提供了一个子类Stack类用来模拟“栈”这种数据结构。Stack具有的方法如下:
·push(Object)
·pop()
·peek()
3.固定长度的List
Arrays.ArrayList类:可以将一个数组或者指定个数的对象转换成一个List集合。不能进行插入和删除操作,只能遍历。
五.Queue接口
Queue接口模拟队列这种特殊的数据结构,主要的方法如下:
add(),offer(),element(),peek(),poll(),remove()
1.LinkedList实现类
LinkedList类既可以当做双向队列来使用,也可以当做栈来使用,还可以当做List集合来使用。
LinkedList类与ArrayList和Vector类的实现机制完全不同,ArrayList和Vector类内部是以数组的形式保存元素,所以随机访问性能较好,而LinkedList类是以链表的形式保存元素,所以随机访问性能较差,但是在迭代访问元素,插入、删除元素方面性能较好。
关于List集合实现类的选择问题:
· 如果需要遍历集合中的元素,对于ArrayList和Vector类最好使用随机访问(get())的方法,对于LinkedList类最好使用迭代器遍历。
· 如果需要经常执行插入和删除操作来改变集合的大小,则应该选用LinkedList类,而不要使用ArrayList类和Vector类。
· 如果需要多条线程同时访问List集合,则可以考虑使用Vector类来同步实现。
2.PriorityQueue实现类
对于PriorityQueue集合中的元素也是按照大小排序,排序的规则与TreeSet类相同,也分自然排序和定制排序两种。
六.Map接口
首先可以将Map接口理解成一个特殊的Set接口,只是该Set接口中保存的元素都比较特殊,每个元素都是一个Entry对象,Entry类封装了一个key-value对,它有三个方法:
·Object getKey()
·Object getValue()
·Object setValue(value)
其次也可以将Map接口理解成一个特殊的List接口,只是List接口中用整数值做索引,而Map接口中用key值做索引,key可以为任意对象。
Map接口用于保存映射数据,它里面保存有两组数据,一组用来保存key,一组用来保存value。Key不允许重复。Map有时也被称为字典或者关联数组。
Map接口提供的方法:
·添加元素:put(Object key,Object value),putAll(Map m)
·删除元素:remove(Object key)
·清除所有元素:clear()
·获取元素:get(Object key)
·测试:containsKey(key),containsValue(value),isEmpty()
·集合大小:size()
·转化:Collection values(),Set keyset(),Set entrySet()
1.HashMap和Hashtable类
HashMap类和Hashtable类的关系就像ArrayList和Vector类的关系一样。
HashMap和Hashtable类的区别:
·Hashtable是一个线程安全类,而HashMap不是线程安全的。但是HashMap性能比Hashtable性能高一些。
·Hashtable不允许null作为key或者value,而HashMap允许。但在HashMap集合中最多有一个key为null,但是可以有多个value为null。
HashMap和Hashtable类也不能保证其中key-value对的顺序,但是它们中的key必须实现equals和hashCode方法。
HashMap和Hashtable类判断两个key值是否相等标准:通过equals方法比较返回true,并且具有相同的hashcode。
HashMap和Hashtable类判断两个value值是否相等标准:通过equals方法比较返回true。
与HashSet类似,尽量不要使用可变对象作为HashMap和Hashtable的key。
HashMap的子类LinkedHashMap:与HashMap不同的是它可以维护元素的迭代顺序,在性能上略差于HashMap,迭代速度却高于HashMap。
Hashtable的子类Properties类:
Properties类用来将Map对象与属性文件关联起来,从而可以将Map对象中的key-value对加入到属性文件,同时也可以将属性文件中的内容加入到Map对象中。
由于属性文件中的“属性名”和“属性值”都是字符串类型,所以Properties文件中的key和value也都是字符串类型。
Properties类主要提供如下几个方法:
·String getProperty(String key)
·String getProperty(String key,String defaultValues)
·void setProperty(String key,String value)
·void load(InputStream is)
·void store(OutputStream os,String comments)
3.SortedMap接口和TreeMap实现类
与SortedSet接口和TreeMap实现类完全类似。
4.WeakHashMap实现类
WeakHashMap类与HashMap类基本相同,不同的是HashMap的key保留了对实际对象的强引用,而WeakHashMap类的key保留了对实际对象的弱引用。
5.IdentityHashMap类
IdentityHashMap类与HashMap类基本相同,不同的是IdentityHashMap类在判断key值相等时,必须保证代表key值的两个对象完全相等时才认为是相等的。
6.EnumMap类
EnumMap是一个与枚举类一起使用的Map实现,它要求key值必须是一个枚举类的枚举值,创建EnumMap类时必须显示或者隐式的指定它对应的枚举类。
EnumMap不允许使用null作为key值,但是允许null作为value值。
Map集合的选择问题:
·HashMap和Hashtable类的效率基本相同,但HashMap的性能可能比Hashtable要好一些,因为HashMap没有实现同步操作。
·TreeMap类的性能不如HashMap,但是TreeMap类中的key-value对都是有序的。
·LinkedHashMap的性能比HashMap略差一点,因为它要维护key的插入顺序。
·EnumMap的性能最好,但是它要求必须要将一个枚举类中的元素作为key。
七.HashSet和HashMap的性能选项
桶:hash表中可以存储元素的位置。
HashSet和HashMap的hash表都有以下性能选项:
·容量(capacity):hash表中桶的数量
·初始化容量(initialCapacity):创建hash表时指定的桶的数量。
·尺寸(size):当前散列表中记录的数量
·负载因子(loadFactor):size/capacity,轻负载的散列表具有冲突少,插入方便,易查询的优点。
负载极限:负载极限的值在0-1之间,当超过负载极限时,会成倍的增加容量(rehashing)。
八.操作集合的工具类Collections
Java提供了一个操作Set,List,Map等集合的工具类:Collections。
1.排序操作
Collections提供了一下几个方法用于对List集合进行排序(都是静态的):
·reverse(list):反转集合中的元素
·shuffle(list):对集合中的元素进行随机排序
·sort(list):根据自然顺序对集合中的元素进行排序
·sort(list,comparator):根据定制顺序对集合中的元素进行排序
·swap(list,i,j):将i和j处的元素进行交换
·rotate(list,i):将i和list.length-1-i处的元素进行交换
2.查找、替换操作
Collections提供了一下几个方法用于对List集合进行查找、替换(都是静态的):
·binarySearch(list,object):查找指定元素在list中的索引,但执行此方法前必须保证list已经处于有序状态。
·max(collection):按照自然排序查找collection中的最大值
·max(collection,comparator):按照定制排序查找collection中的最大值
·min(collection):按照自然排序查找collection中的最小值
·min(collection,comparator): 按照定制排序查找collection中的最小值
·fill(list,object):使用指定元素object替换list中的所有元素
·frequency(colletion,object):返回集合collection中object元素出现的次数
·replaceAll(list,oldval,newval):用新的元素newval替代list中所有旧的元素oldval
3.同步控制
Collections提供了多个synchronizedXxx方法用来同步集合对象,可以解决多线程并发访问集合时的线程安全问题。
4.设置不可变的集合
Collections提供了三个方法返回一个不可变的集合:
·emptyXxx():返回一个空的不可变的集合对象。
·singleton(object):返回一个只包含一个元素object的集合对象。
·unmodifiableXxx(colletion or map):返回一个不可变的视图。