一、什么是容器
在使用Java编程的过程中,我们经常使用数组来存储对象的集合,但有时候会遇到这样一个问题:我们没法确定数组的长度,只有当程序运行后我们才能知道具体有多少个对象。一种解决办法是定义一个很大的数组,这无疑会浪费很多存储资源;另一种方法便是使用容器,所谓容器我们也可以理解为一个动态的数组,我们不需要提前设定存储对象的数目,有多少对象就可以添加多少对象,系统会自动为我们分配资源。
二、容器的分类
容器大体可以分为两类:一类是Collection对象,它用来保存单一的元素;另一类是Map对象,它用来保存键值对。下图展示了两类容器的具体分类:
容器分类图中的Abstract字头一般是接口的具体实现,所以像ArrayList、LinkedList、HashSet、HashMap等容器并非是直接继承接口,而是继承接口的实现类。此外,从图中我们可以看出Collection对象都继承了Iterable接口,Collection对象都可以通过调用iterator()方法来生成迭代器对象,因而对所有的Collection对象我们都可以使用Foreach语法,如:
List<String>list = new ArrayList<String>(Arrays.asList("hello", "world"));
for (String s:list)
System.out.println(s);
但是Map对象没有继承Iterable接口,因而不能使用Foreach语法,但是Map对象也可以通过keySet()生成一个关于”键“的序列,从而间接使用Foreach语法。
三、容器类的区别
(1)Collection
List:List中的数据都是按照插入的顺序存储的,其中ArrayList适合用于有大量随机访问的情况,而LinkedList适用于经常需要插入和删除元素的情况。
Set: Set中不能存储重复的元素,HashSet被设计用来快速访问,其存储的元素并没有什么规律;TreeSet保持元素处于排序状态,排序的规则可以通过比较器定义;LinkedHashSet既保持了元素的插入顺序,又能够实现快速访问。
Queue: Queue是一种“先进先出”的容器,LinkedList实现了Queue接口,因而常被用来实现堆栈、队列等数据结构;PriorityQueue则是一种优先级队列,它所弹出的下一个元素是最需要的元素(优先级最高的元素),默认的排序是自然顺序,但也可以通过定义比较器来修改这个规则。
(2)Map
HashMap用于快速访问,TreeMap保持“键”始终处于排序状态,LinkedHashMap保持元素的插入顺序同时也具备快速访问的能力。
四、关于容器的使用
(1)在创建一个容器类的时候,应尽量使用接口,除非你需要用到类中额外定义的函数(接口中没有),如:
List<String>list = new ArrayList<String>();推荐
ArrayList<String>list = new ArrayList<String>();不推荐
(2)Arrays.asList()返回的是一个长度的固定的列表,其底层实现还是数组,因而不能对其进行删除或者添加操作,此外使用Arrays.asList()方法时,需注意
String[] str = {"hello", "world", "!"};
List<Integer>list1 = new ArrayList<String>(Arrays.asList(str));//相当于新建了一个副本,对原数组无影响
List<Integer>list2 = Arrays.asList(str);//对list2的改动相当于直接在原数组上做改动
(3)LinkedList可以通过listIterator()方法生成一个ListIterator迭代器,它可以双向移动,同时还有许多Iterator没有的函数。
(4)容器不能持有基本类型,但是自动包装机制会仔细执行基本类型到容器中所持有的包装器类型之间的双向转换。
(5)新程序中不应该使用过时的Vector、Hashtable和Stack。