集合的概念:
Collection接口
Set接口及其实现类
List接口及其实现类
Queue接口及其实现类
Map接口及其实现类
HashMap和HashSet的性能选项
Collection工具类
集合概述
为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组)。java提供集合类,集合类主要负责保存,盛装其他数据,因此集合类也被称为容器类。所有集合类都位于java.util包下 。
java的集合类主要由两个接口派生儿出:Collection和Map.Collection和Map是java集合的根接口,这两个接口又包含了一些子接口或实现类。
Collection<--Set(无序集合,元素不可重复)
EnumSet SortedSet<--TreeSet HashSet<---LinkedHashSet
Queue <--Deque<---LinkedList
Queue <--PriorityQueue
Collection<--List(有序集合,元素可重复)
List<--LinkedList
List<--ArrayList
List<--Vector<--Stack
Map<--EnumMap
Map<--IdentityHashMap
Map<--HashMap<--LinkedHashMap
Map<--Hashtable<--Properties
Map<--SortedMap<--TreeMap
Map<--WeakHashMap
Collection接口是List,Set和Queue接口的父接口,该接口里定义的方法即可用于操作Set集合,也可用于操作List和Queue集合。
Collection提供了大量添加,删除,访问的放法来访问集合元素。
Iterator接口
Iterator接口也是Java集合框架的成员,但它与Collection系列,Map系列的集合不一样:
Collection系列集合,Map系列集合主要用于盛装其他对象,而Iterator则主要用于遍历(即迭代访问)Collection集和中的元素,Iterator对象也被称为迭代器。
Iterator接口里定义了如下4个方法:
-boolean hasNext():如果被迭代的集合和元素没有被遍历,则返回true.
-Object next():返回集合里下一个元素。
-void remove():删除集合里上一次next方法返回的元素
-void forEachRemaining(Consumer action),这是Java8为Iterator新增的默认方法,该方法可使用Lambda表达式来遍历集合元素。
foreach循环遍历集合元素
使用JDK1.5提供的foreach循环来迭代访问集合元素更加便捷。
当使用foreach循环迭代访问集合元素时,该集合也不能被改变,否则将引发ConcurrentModificationException异常。
使用Predicate操作集合
java8 为Collection集合新增了一些需要Predicate参数的方法,这些方法可以对集合元素进行过滤。程序可使用Lambda表达式构建Predicate对象。
Java8新增的Stream操作
Java8新增了Stream,IntStream,LongStream,DoubleStream等流式API。
独立使用Stream的步骤如下:
-(1)使用Stream或XxxxStream的builder()类方法创建该Stream对应Builder.
-(2)重复调用Builder的add()方法向该流中添加多个元素。
-(3)调用Builder的build()方法获取对应的Stream.
-(4)调用Stream的聚集方法。
Collection接口提供了一个stream()默认方法,该方法可返回该集合对应的流,接下来即可通过流API来操作集合元素。由于Stream可以对集合元素进行整体的聚集操作,因此Stream极大了丰富了集合功能。
HashSet类
HashSet是Set接口的典型实现,大多时候使用Set集合就是使用这个实现类
。HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值来决定该对象在HashSet中存储位置。如果有两个元素通过equals方法比较返回true,但他们的hashCode()方法返回值不相等,HashSet将会把它们存储在不同位置,也就可以添加成功。
HashSet的特征
不能保证元素的排列顺序,顺序可能与元素的添加顺序不同,元素的顺序可能变化。
HashSet 不是同步的,如果多个线程同时访问HashSet,如果有2条或者2条以上线程同时修改了HashSet集合时,必须通过代码来保证其同步。
集合元素值可以是null.
LinkedHashSet
LinkedHashSet集合也是根据元素hashCode值来决定元素存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是可以插入的顺序保存的。也就是说,当遍历LinkedHashSet集合里元素时,HashSet将会按元素的添加顺序来访问集合里的元素。
LinkedHashSet 需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。
TreeSet
TreeSet 是SortedSet接口的唯一实现,正如SotedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态。与前面HashSet集合相比,TreeSet还提供了如下几个额外的方法:
-Object first():返回集合中的第一个元素。
-Object last():返回集合中的最末一个元素。
-Object lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元素不需要是TreeSet的元素)
-Object higher(Object e):返回集合中位于指定元素之后的元素(即指定元素的最小元素,参考元素不需要是TreeSet的元素)。
-SortedSet subSet(formElement,toElement):返回此Set的子集合,范围从fromElement(包含)到toElement(不包含)。
-SortedSet headSet(toElement):返回此Set的子集,由于小于toElement的元素组成。
-SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。
TreeSet采用红黑树的数据结构对元素进行排序。TreeSet支持两种排序方法:自然排序和定制排序。
-自然排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之前大小关系,然后将集合元素按升序排列,这种方式就是自然排序。
-定制排序:TreeSet借助Comparator接口的帮助。该接口里包含一个的int compare(Tol,To2)方法,该方法用于比较o1和o2的大小。
EnumSet
EnumSet是一个专为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnmuSet时显示或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类的定义顺序来决定集合元素的顺序。
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑,高效,因此EnumSet对象占用内存很小,而且运行效率很好。尤其是当进行批量操作(如调用containsAll和retainAll方法)时,如其参数也是EnumSet集合,则该批量操作的执行速度也非常快。
EnumSet集合不允许加入null元素。如果试图插入null元素,EnumSet将抛出NullPointerException异常。如果仅仅只是试图测试是否出现null元素,或删除null元素都不会抛出异常,只是删除操作将返回false,因为没有任何null元素被删除。
List接口
List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。因为List集合默认按元素的添加顺序设置元素的索引,例如第一次添加的元素索引为0,第二次添加的元素索引为1......
List作为Collection接口的子接口,当然可以使用Colletion接口里全部方法。而且由于List是有序集合,因此List集合里包含了根据索引来操作集合元素的方法。
ListIterator与Iterator接口不同,它不仅可以向后迭代,它还可以向前迭代。
ListIterator包含增加了如下3个方法:
-boolean hasPrevious(): 返回该迭代器关联的集合是否还有上一个元素。
-Object previous(): 返回该迭代器的上一个元素。
-void add():在指定位置插入一个元素。
Itrator(迭代),Enumeration(枚举)
迭代是取出集合中元素的一种方式。
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
用法:
for(Iterator ite=iterator();iter.hasNext();)
{
System.out.print(iter.next());
}
Iterator iter = l.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
迭代注意事项
迭代器在Collection接口中是通用的。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException
迭代器的next方法返回值类型是Object,所以要记得类型转换。
比较Comparator
比较Comparator
比较函数强行对某些对象collection进行整体排序。可以将Comparator传递给sort方法(如Collections.sort),从而允许在排序上实现精确控制。
public class User{
int a;
String s;
public User(int a,String s ){
this.a=a;
this.s=s;
}
}
ArrayList<User> arr=new ArrayList();
arr.add(new User(21,"21");
arr.add(new User(12,"12");
arr.add(new User(3,"3");
arr.add(new User(14,"14");
arr.add(new User(5,"5");
arr.add(new User(26,"26");
Collection.sort(arr);
ArrayList与Vector
ArrayList和Vector类都是基于数组实现的List类,所以ArrayList和Vector类封装了一个动态再分配的Object[]数组。每个ArrayList或Vector对象有一个capacity属性,这个capacity表示它们所封装的Object[]数组的长度。当向ArrayList或Vector中添加元素时,它们的capacity会自动增加。
ArrayList和Vector的显著区别是;ArrayList是线程不安全的,当多条线程访问同一个ArrayList集合时,如果有超过一条线程修改了ArrayList集合,则程序必须手动保证该集合的同步性。但Vector集合则是线程安全的,无需程序保证该集合的同步性。
固定长度的List
Arrays工具类里提供了asList(Object...a)方法,该方法可以把一个数组,或指定个数的对象转换成List集合,这个List集合即不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList的实例。
Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可增加,删除该集合里的元素。
Queue接口
Queue用于模拟了队列这种数据结构,队列通常是指,“先进先出”(FIFO)的容器。队列的头部保存在队列中存放时间最长的元素。队列的尾部保存在队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问元素(poll)操作返回队列头部的元素。通常,队列不允许随机访问队列中的元素。
LinkedList
它是List接口的实现类这意味着它是一个List集合,可以根据索引来随机访问集合中的元素。除此之外,LinkedList还实现了Deque接口,Deque接口是Queue接口的子接口,它代表一个双端队列。
LinkedList不仅可以当成双端队列使用,也可以当成“栈”使用,因为该类里还包含了pop(出栈)和push(入栈)两个方法。除此之外,LinkedList接口,所以还被当成List使。
ArrayList与LinkedList
LinkedList与ArrayList,Vector的实现机制完全不同,ArrayList,Vector内部一数组的形式来保存集合中的元素,因此随机访问集合元素上有较好的性能;而LinkedList内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但在插入,删除元素时性能非常出色(只需要改变指针所指的地址即可);
类Stack<E>
java.util
类Stack<E>
java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractList<E>java.util.Vector<E>
java.utilStack<E>
所有以实现的接口:
Serializable,Cloneable,Iterable<E>,
Collection<E>,List<E>,RandomAccess
接口Query<E>
java.util
接口Queue<E>
类型参数:
E-集合中所保存的元素类型。
所有超级接口:
-Collection<E>,Iterable<E>
所有已知接口:
-BlockingQueue<E>
所有已知实现类:
-AbstractQueue,ArrayBlockingQueue,ConcurrentLinkedQueue,
DelayQueue,LinkedBlockingQueue,LinkedList,
PriorityBlockingQueue,PriorityQueue,SynchronousQueue
PriorityQueue
PriorityQueue是一个比较标准的队列实现类,之所以说它是比较标准的队列实现,而不是绝对标准的队列实现是因为:
PrioprotyQueue保存队列元素的顺序并不是按加入队列的顺序,而是按队列元素的大小进行重新排序。因此当调用peek方法或者poll方法来取出队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中最小的元素。
理解Map
Map里key集合和Set集合里元素的存储形式也很像,Map子类和Set子类在名字也惊人地相似:如Set接口下有HashSet,LinkedHashSet,SortedSet(接口),TreeSet,EnumSet等实现类和子接口,而Map接口下则有HashMap,LinkedHashMap,SortedMap(接口),TreeMap,EnumMap等实现类和子接口。正如它们名字所暗示的,Map的这些实现类和子接口中key集存储形式对应Set集合中元素的存储形式完全相同。
如果把Map所有value放在一起来看,它们又非常类似于一个List:元素与元素值可以重复,每个元素可以根据索引来查找,只是Map中的索引不再使用整数值,而是以另一对象来作为索引。如果需要从List集合中取出元素,需要提供该元素的数字索引。
HashMap和Hashtable
HashMap和HashMap都是Map接口的典型实现类,它们的区别如下:
-Hashtable是一个线程不安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能高一点;但如果有多条线程访问同一个Map对象时,使用Hashtable实现类会更好。
-Hashtable不允许使用null作为Key和value,如果试图把null值放进Hashtable中,将会引发NullPointException异常;但HashMap可以使用null作为key或value.
LinkedHashMap
LinkedHashMap也使用双向链表来维护key-value对的次序,该链表定义了迭代顺序,该迭顺序与key-value对的插入顺序保持一致。
LinkedHashMap可以避免需要对HashMap,Hashtable里的Key-value对进行排序(只要插入key-value对时保持顺序即可)。同时又可避免使用TreeMap所增加的成本。
Map接口
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value,另外一组用于保存Map里的value,key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较总是返回false.
key和value之间存在单向一对一关系,即通过指定的key,总能找到唯一的,确定的value.从Map中取出数据时,只要给出指定的key,就可以取出对应的value.
Properties类
Properties类是Hashtable类的子类,正如它的名字暗示的该对象在处理属性文件时特别方便(Windows操作平台上的ini文件就是一种属性文件)。Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入属性文件,也可以把属性文件中的属性名=属性值加载到Map对象中。由于属性文件里的属性名,属性值只能是字符串类型,所以Properties里的key,value都是字符串类型,该类提供了如下三个方法来修改Properties里的key,value值。
-String getProperty(String key):获取Properties中指定属性名对应的属性值,类似于Map的get(Object key)方法。
-String getProperty(String key ,String defaultValue):该方法与前一个方法基本相似。该方法多一个功能,如果Properties中不存在指定key时,该方法返回默认值。
-Object setProperty(String key,String value):设置属性值,类似Hashtable 的put方法。
TreeMap
Map接口也派生了一个SortedMap子接口,SortedMap也有一个TreeMap实现类。
与TreeSet类似的是,TreeMap也是基于红黑树对TreeMap中所有Key进行排序,从而保证TreeMap中所有key-value对处于有序状态。TreeMap也有两种排序方式:
自然排序:TreeMap的所有key必须实现Comparable接口,而且所有key应该是同一个类的对象,否则将会抛出ClassCastException异常。
-定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中所有key进行排序。采用定制排序时不要求Map的key实现Comparable接口。
WeakHashMap
WeakHashMap与HashMap的用法基本相似。但与HashMap的区别在于,HashMap的key保留对实际对象强引用,着意味着只要该HashMap对象不被销毁,该HashMap对象所有key所引用的对象不会被垃圾回收,HashMap对象所有key所引用的对象不会被垃圾回收,HashMap也不会自动删除这些所对应的key-value对象;
但WeakHashMap的key只保留对实际对象的弱引用,这意味着如果该WeakHashMap对象所有key所引用的对象没有被其他强引用变量所引用 ,则这些key所引用的对象可能被垃圾回收,WeakHashMap也可能自动删除这些key所对应的key-value对象。
IdentityHashMap
IdentityHashMap实现类的实现机制与HashMap基本相似,但它在处理两个key相等时比较独特:在IdentityHashMap中,当且仅当两个key严格相等(key1==key2)时,IdentityHashMap才认为两个建相等,
对于普通HashMap而言,只要key1和key2通过equals比较返回true,且它们的hashCode值相等即可。
EnumMap
EnumMap是一个与枚举类一起使用的Map实现,
EnumMap中所有key都必须是单枚举类的枚举值。创建EnumMap时必须显示或隐式指定它对应的枚举类。
EnumMap在内部以数组形式保存,所以这种实现形式非常紧凑,高效。
EnumMap根据key的自然顺序(即枚举值在枚举类中的定义顺序)来维护key-value对的次序。当程序通过keySet(),entrySet(),values()等方法来遍历EnumMap时即可看到这种顺序。
EnumMap不允许使用null作为KEY值,但允许使用null作为value.如果试图使用null作为key将抛出NullPointerException异常。如果仅仅只是查询是否包含值为null的key,或者仅仅只是使用删除值为null的key,都不会抛出异常。
HashSet和HashMap的性能
因为HashSet和HashMap,Hashtable都使用hash算法来决定其元素(对HashMap则是key)的存储,因此HashSet,HashMap的hash表包含如下属性:
-容量(capacity):hash表中桶的数量。
-初始化容量(initial capacity):创建hash表时桶的数量。HashMap和HashSet都允许在构造器中指定初始化容量。
-尺寸(size):当前散列表中记录的数量。
-负载因子(load factor):负载因子等于“size/capacity".负载因子为0,表示空的hash表,0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少,适宜插入与查询的特点(但是使用Iterator迭代元素时会变慢)。
Collections
Java提供了一个操作Set,List和Map等集合的工具类:Collections,该工具类里提供了大量方法对集合元素进行排序,查询和修改等操作。
Collections还提供了将集合对象设置不可变,对集合对象实现同步控制等方法。
Enumeration接口
Enumeration接口是Iterator迭代器的”古老版本“,从JDK1.0开始,Enumeratio接口就已经存在了(Iterator从JDK1.2才出现)。Enumeration接口比Iterator小,只有两个名字很长的方法:
-boolean hashMoreElements():如果此迭代器还有剩下的元素返回True.
-Object nextElement():返回该迭代器的下一个元素,如果还有的话(否则抛出异常)。
算法
Collection类中的静态方法
用于排序,搜索,混排和数据操纵
方法的第一个参数要执行操作的集合
重要异常:
-ClassCastException
-UnsupportedOperationException
Class AlgoithmExample{
public static void main (String args[]){
LinkedList link= new LinkedList();
link.add(new Integer(10));
link.add(new Integer(35));
link.add(new Integer(23));
link.add(new Integer(54));
link.add(new Integer(36));
Comparator cmp = Collctions.reverseOrder();
Collections.sort(link,cmp);
Iterator it =link.iterator();
System.out.println("逆序排序列表为:");
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("给定列表中的最大值为:"+Collctions.max(link));
System.out.println("给定列表中的最小值为:"+Collections.min(link));
}
}
集合框架的优点
提供一组可用的集合接口
提供有效的数据结构和算法
可以方便地扩展或改写集合
接口的实现都是可交换的
使设计新API的工作降到最少
接口和算法的可重用性
java集合随笔
最新推荐文章于 2022-11-10 22:14:06 发布