要谈编程语言引入集合的原因,就不得不谈到集合与数组的差别:
(1)长度:数组是固定长度;集合是可变长度。
(2)元素性质:数组的元素可以是原生数据类型,也可以是引用类型;集合的元素只能是引用类型,原生数据类型必须装箱(jdk5.0之后有自动装箱和拆箱功能)之后才能放入集合之中。
(3)元素类型:数据在定义之初就确定了存储数据的类型,因此也只能存储单一一种数据类型;集合则可以存储不同的数据类型,虽然在实际应用中通常也只用于存储同一类型的数据。
Java中的集合主要集中在两部分—— java.util包和java.util.concurrent中。其中,后者是在前者的基础上,定义了一些实现了同步功能的集合。这里主要关注java.util包中的集合,可以简单地划分为三类:List、Set和Map。对应的UML图如下:
常用的ArrayList、LinkedList、Vector、HashSet、TreeSet都是Collection接口的具体实现类;而HashMap、TreeMap、Hashtable都是Map接口的实现类。因此,我们要讲集合,必须从Collection接口和Map接口入手。
Collection接口定义了集合常见的操作:
集合的遍历是实际开发过程中常见的需求。这里我们以Collection的具体实现类ArrayList为例,介绍集合的三种遍历方法,并在集合遍历的基础上将上述主要的集合操作方法进行演示。具体如下:
package test; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class CollectionTest { public static void main(String[] args) { //创建集合对象 Collection<String> list = new ArrayList<String>(); //添加元素 list.add("string1"); list.add("string2"); list.add("string3"); list.add("string4"); list.add("string5"); //方法一:用增强的for循环遍历集合 for(String element :list) { System.out.println(element); } //删除元素 list.remove("string5"); System.out.println("--------------------"); //判断集合中是否包含“string5” System.out.println(list.contains("string5")); //判断集合是否为空 System.out.println(list.isEmpty()); //计算集合中的元素个数 int number = list.size(); System.out.println(number); System.out.println("--------------------"); //方法二:数组遍历法,将集合转化为数组,基于数组遍历集合 //首先,将集合转化为数组 Object[] array = list.toArray(); //然后,用普通的for循环遍历集合(当然也可以用增强的for循环) for(Object element : array) { System.out.println(element); } System.out.println("--------------------"); //方法三:采用迭代器遍历数组 for(Iterator<String> iterator = list.iterator(); iterator.hasNext();) { String string = iterator.next(); System.out.println(string); } } }
ArrayList、LinkedList、Vector等具体类并不直接实现Collection接口,而是实现Collection的子接口List。List子接口定义了Collection所不具备的功能,其特点是有序、可重复。List的特有功能包括:
具体实现类及其特点简单概括如下:
(1)ArrayList:底层数据结构是数组,查询快,增删慢;
(2)Vector :底层数据结构是数组,查询快,增删慢,线程安全,效率低;
(3)LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全,效率高。
同样,HashSet、TreeSet等具体类也并不直接实现Collection接口,而是实现Collection的子接口Set。Set子接口定义了Collection所不具备的功能,其特点是无序、唯一。
Set的具体实现类及其特点简单概括如下:
(1)HashSet:底层数据结构是哈希表;依赖hashCode()和equals()两个方法;
(2)LinkedHashSet:底层数据结构是链表和哈希表,由链表保证元素有序,由哈希表保证元素唯一;
(3)TreeSet:底层数据结构是红黑树,保证元素排序的方式自然排序、比较器排序,根据比较的返回值是否是0来决定元素的唯一性。
Map存储的是键值对形式的元素。键唯一,值可以重复。Map的主要功能总结如下:
添加元素:put
删除元素:clear/remove
判断是否包含值\键:containsValue\ containsKey
判断是否为空:isEmpty
获取值\键的集合:get\keySet\values
获取长度:size
在此以HashMap为例演示集合的遍历:
package test; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class MapTest { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "string1"); map.put(2, "string2"); map.put(3, "string3"); map.put(4, "string4"); map.put(5, "string5"); //遍历方法一:以键找值 Set<Integer> set = map.keySet(); for(Integer key : set) { String value = map.get(key); System.out.println(key + " : " + value); } System.out.println("--------------------"); //删除元素 map.remove(2); //判断是否为空 System.out.println(map.isEmpty()); //获取长度 System.out.println(map.size()); System.out.println("--------------------"); //遍历方法二:键值对对象 Set<Entry<Integer, String>> set2 = map.entrySet(); for(Map.Entry<Integer, String> entry : set2) { Integer key = entry.getKey(); String value = entry.getValue(); System.out.println(key + " + " + value); } } }
Map的具体实现类及其特点简单概括如下:
(1)HashMap:基于哈希表的Map接口实现,哈希表的作用是用来保证键的唯一性的,要保证唯一性必须重写hashCode()和equals()方法;
(2)LinkedHashMap:基于哈希表和链接列表实现,具有可预知的迭代顺序,由哈希表保证键的唯一性,由链表保证键的有序性
(3)TreeMap:是基于红黑树的Map接口的实现,保证元素排序的方式有自然排序和比较器排序。