黑马程序员----JAVA中各种容器的区别和方法

来源:互联网 发布:eviews软件中文版下载 编辑:程序博客网 时间:2024/05/20 00:16

------Java培训、IOS培训、.NET培训、期待与您交流!------

首先容器分为collection和map两大接口

Collection中持有一种特定类(包含其子类)的对象,这也称作其元素,这些元素可以重复,有序或者无序,可以用迭代器遍历;

Map则是可以持有两种类(包含其子类)的对象,其中元素中两个对象的实例通过Map.Entry一一映射,Set<Map.Entry<K,V>> entrySet 方法返回对应的映射视图.

Collection中又有List,Set,和Queue3种常用的接口:

List必须按照插入的顺序保存元素,

其中经常用到的实现子类有ArrayList,LinkedList以及Stack;

Arraylistlist接口大小可变数组的实现,数组大小在初始化后是固定的,但是将其用Arrays.aslist()方法传递给Arraylist后,其大小可以改变,而传递给其它list则不行,长于随机访问元素,但是在list的中间插入和移除元素时较慢.

其构造方法有三:

Arraylist():构造一个初始容量为10的空列表。

Arraylist(Collection<? extends E> c):构造一个包含指定Collection的元素的列表,这些元素是根据该Collection的迭代器返回它们的顺序排列的。

Arraylist(int initialCapacity):构造一个初始容量为指定大小的空列表。

我对Arraylist的困惑是其移除指定索引N到M的removeRange方法居然是protected的;

Linkedlist:list接口的链接列表的实现,所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。因为实现了Queue接口,可以理解为双向队列,所以它通过代价较低的在List中间进行插入和删除操作,更加便于顺序访问,在容器容量大的时候优势明显,但是随机访问方面较弱。

其构造方法不同于Arraylist的在于

Arraylist()是构造一个空列表,

而且也有很多Arraylist中不同的方法:

peek():获取但不移除第一个元素,空列表则返回null;

poll():获取且移除第一个元素;

Stack:栈通常指的是后进先出“LIFO"的容器,其顶部是堵塞的,通过push()方法将元素压至栈底,pop方法移除并返回栈顶元素。

Set中不包含重复元素,包括null,也就是说其最多包含一个null元素,重复在Set中定义为满足equals()方法,其常用实现子类有HashSet和TreeSet,Set中容器没有下标,所以无法通过指定位置访问元素。

HashSet中元素位置有hash表支持,所以其持有对象必须定义hashcode()方法,否则会出现重复对象,支持null元素.每个元素的顺序并非不变,虽然HashSet中并不支持获取特定位置元素,因为其顺序不固定.

TreeSet是按照结果的升序保存对象,顾名思义,底层为树结构,使用它可以提取有序的序列,所以其持有对象的类必须实现comparable接口,依据其中定义的compareTo方法来排序,默认的是自然升序。其有一个返回按降序排列的Iterator的descendingIterator方法;以及返回其比较器Comparator的comparator()方法。

LinkedHashSet:在容器中的排列是以hashcode方法散列,而用迭代器遍历时,结果会按元素插入的顺序显示。所以避免了HashSet中杂乱无章的排序和迭代,而又避免了TreeSet中的开支.

下面测试一下各种Set的不同:

public class TestCollections {
public static Set<Integer> fill(Set<Integer> c){
Random ran=new Random();
for(int i=0;i<20;i++){
c.add(ran.nextInt(1000));
}
return c;
}
public static void itering(Set<Integer> c){
Iterator<Integer> iter=c.iterator();
while(iter.hasNext())
System.out.print(iter.next()+" ");
System.out.println();
}
public static void main(String [] args){
HashSet<Integer> hs=new HashSet<Integer>(fill(new HashSet<Integer>()));
TreeSet<Integer> ts=new TreeSet<Integer>(hs);
LinkedHashSet<Integer> linhash=new LinkedHashSet<>(hs);
System.out.println(hs);
System.out.println(ts);
System.out.println(linhash);
itering(hs);
itering(ts);
itering(linhash);
}
}

fill方法将在容器中用随机数字填充容器,输出为下

[513, 579, 611, 551, 44, 941, 589, 685, 399, 16, 849, 881, 882, 758, 248, 632, 635, 637, 702, 766]
[16, 44, 248, 399, 513, 551, 579, 589, 611, 632, 635, 637, 685, 702, 758, 766, 849, 881, 882, 941]
[513, 579, 611, 551, 44, 941, 589, 685, 399, 16, 849, 881, 882, 758, 248, 632, 635, 637, 702, 766]
513 579 611 551 44 941 589 685 399 16 849 881 882 758 248 632 635 637 702 766 
16 44 248 399 513 551 579 589 611 632 635 637 685 702 758 766 849 881 882 941 
513 579 611 551 44 941 589 685 399 16 849 881 882 758 248 632 635 637 702 766 

可见只有treeset会对元素进行排序,而hashset以及linkedHashSet都会对元素进行散列,没有顺序。

Queue:意思为队列,队列通常以先入先出(FIFO)的顺序排序各种元素,只能在一端插入元素,另一端删除元素,放入容器的顺序和取出的顺序是一样的,一般也不允许null元素,其常用的实现子类有linkedList和PriorityQueue;

PriorityQueue:优先级队列声明下一个弹出元素是最需要的元素,相当于可以插队,这种优先级通过元素的comparator()方法定义,默认是自然排序,PriorityQueue不允许null元素,其构造器PriorityQueue()是构造一个默认容量为11的空容器,按照自然顺序排序.其也没有通过下标访问元素的方法。

Map中常用的有HashMap,TreeMap以及LinkedHashMap.

HashMap:同样通过hashcode()方法排列其中元素,Map中可以通过get(key)方法获取对应的值,当容器容量很大时,访问效率很低,而用HashMap则效率很高,因为其采用了散列码方法,访问速度最快.

LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得"键值对"的顺序是去插入顺序,可以在构造器中设定LinkedHashMap,使之采用基于访问的最近最少使用算法,于是没有被访问或者很少被访问的元素会出现在队列的前面,便于垃圾清理。

TreeMap:查看“键”时,它们会被排序(次序由comparable或者Comparator)决定,TreeMap的特点在于,所得到的结果是经过排序的。它也是唯一的带有subMap()方法的Map,它可以返回一个指定范围的子Map。

这三种Map的区别和三种Set的区别是一样的,因为Map的Key其实就是一个Set,而确定了Key值,value也就确定了。

上述所有的Collection和Map都是线性不安全的,当多进程访问并修改了容器时,必须实现外在同步,而ConcurrentHashMap则是一种线性安全的Map,不涉及同步加锁.



0 0
原创粉丝点击