Java集合框架概述
集合就是将若干用途相同、近似的“数据”结合成一个整体。
集合从体系上分为三种:
(1) 列表(List):List集合区分元素的顺序,允许包含相同的元素。
(2) 集(Set):Set集合不区分元素的顺序,不允许包含相同的元素。
(3) 映射(Map):Map集合保存的”键”-“值”对,“键”不能重复,而且一个“键”只能对应一个“值”。
Java集合中只能保存引用数据类型,也就是保存的是对象的地址,而非对象本身。集合中元素相当于引用类型的变量。
Java集合主要包括三种类型:Set(集),List(列表),Map(映射)。
Java集合类框图:
Collection和Iterator接口
在Collection接口中声明了适用于Java集合(只包括Set和List)的通用方法。因此Set和List对象可以调用以上方法,Map对象不可以。
Iterator接口隐藏了底层集合的数据结构,向客户程序提供了遍历各种数据集合的统一接口。
如果集合中的元素没有排序,Iterator遍历集合中元素的顺序是任意的,并不一定与集合中加入元素的顺序是一致的。
Collection接口中的方法:
boolean add(E o) | 确保此 collection 包含指定的元素(可选操作) |
void clear() | 移除此 collection 中的所有元素(可选操作) |
boolean contains(Object o) | 如果此 collection 包含指定的元素,则返回 true |
boolean isEmpty() | 如果此 collection 不包含元素,则返回 true |
Iterator<E> iterator() | 返回在此 collection 的元素上进行迭代的迭代器 |
boolean remove(Object o) | 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作) |
int size() | 返回此 collection 中的元素数 |
Object[] toArray() | 返回包含此 collection 中所有元素的数组 |
Collection方法举例:
public class javatest { public static void main(String args[]) { Collection c = new ArrayList(); c.add("Hello World!"); //添加String类型对象 c.add(new Integer(100)); //添加Integer类型对象 c.add(new Float(2323.45f)); //添加Float类型对象 System.out.println(c.size()); System.out.println(c); } }
List接口以及实现类
List是Collection的子接口,实现List接口的容器中存放的对象是有顺序的,而且可以重复。List容器中存放的对象都有一个整数型的序号,记录该对象在容器中的位置,可以根据序号来访问容器中的元素。
JDK提供实现List接口的类有ArrayList、LinkedList等。相关方法如下:
Object get(int index) Object set(int index,Object obj) void add(int index,Object obj) Object remove(int index) int indexOf(Object obj) int lastIndexOf(Object obj)
List接口举例:
public class javatest { public static void main(String args[]) { List li=new ArrayList(); for(int i=0;i<10;i++) li.add("a"+i); System.out.println(li); li.add(3,"a20"); System.out.println(li); li.set(4,"a30"); System.out.println(li); System.out.println((String)li.get(2)); li.remove(0); System.out.println(li); } }
运行结果如下:
[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
[a0, a1, a2, a20, a3, a4, a5, a6, a7, a8, a9]
[a0, a1, a2, a20, a30, a4, a5, a6, a7, a8, a9]
a2
[a1, a2, a20, a30, a4, a5, a6, a7, a8, a9]
List接口的实现类-ArrayList
java.util.ArrayList实现了List接口,用于描述长度可变的数组列表(底层采用数组实现)。ArrayList允许元素取值为null,提供了一些新增的方法来操作列表的容量的大小。
public ArrayList() public ArrayList(int initialCapacity) public void ensureCapacity(int minCapacity) public void trimToSize()
ArrayList举例:
ArrayList list=new ArrayList(6); list.add("codingwu"); list.add(new Integer(10)); list.add(new Double(10.5)); System.out.println(list.size()); Object item[]=list.toArray(); for(int i=0;i<item.length;i++) System.out.println(item[i]); list.trimToSize();
List接口的实现类-Vector
java.util.Vector实现了List接口,用于描述长度可变的数组向量(底层采用数组实现)。
与ArrayList的区别:Vector是线程安全的(同步),用在多线程环境中,运行效率慢。ArrayList不是线程安全的,用在单线程环境中。
Vector类的新增方法:
public Vector() public Object elementAt(int index) public void removeElement(int index) public void insertElement(Object obj,int index) public boolean removeElement(Object obj) public void removeAllElements() public Object toArray()
Map接口以及实现类
以该接口为根的集合类,用于存储“关键字”(key)和“值”(value)的元素对,其中每个关键字映射到一个值,当需要通过关键字实现对值的快速存取时使用
声明的抽象方法主要有:
查询方法、修改方法
两个主要实现类:
HashTable、HashMap
查询方法
int size() —— 返回Map中的元素个数
boolean isEmpty() —— 返回Map中是否包含元素,如不包括任何元素,则返回true
boolean containsKey(Object key) —— 判断给定的参数是否是Map中的一个关键字(key)
boolean containsValue(Object val) —— 判断给定的参数是否是Map中的一个值(value)
Object get(Object key) —— 返回Map中与给定关键字相关联的值(value)
Collection values() —— 返回包含Map中所有值(value)的Collection对象
Set keySet() ——返回包含Map中所有关键字(key)的Set对象
Set entrySet() —— 返回包含Map中所有项的Set对象
修改方法
Object put(Object key, Object val) —— 将给定的关键字(key)/值(value)对加入到Map对象中。其中关键字(key)必须唯一,否则,新加入的值会取代Map对象中已有的值
void putAll(Map m) —— 将给定的参数Map中的所有项加入到接收者Map对象中
Object remove(Object key) —— 将关键字为给定参数的项从Map对象中删除
void clear() —— 从Map对象中删除所有的项
哈希表
也称为散列表,是用来存储群体对象的集合类结构,其两个常用的类是HashTable及HashMap
哈希表存储对象的方式与前面所讲的数组,Vector及ArrayList不同。数组、Vector及ArrayList中 对象的存储位置是随机的,即对象本身与其存储位置之间没有必然的联系。因此查找一个对象时,只能以某种顺序(如顺序查找,二分查找)与各个元素进行比较, 如果数组或向量中的元素数量很庞大时,查找的效率必然降低
哈希表中,对象的存储位置和对象的关键属性k之间有一个特定的对应关系f,我们称之为哈希(Hash)函数。它使每个对象与一个唯一的存储位置相对应。因而在查找时,只要根据待查对象的关键属性k,计算f(k)的值即可知其存储位置
哈希表相关的一些主要概念:
容量(capacity)—— 哈希表的容量不是固定的,随对象的加入,其容量可以自动扩充
关键字/键(key)—— 每个存储的对象都需要有一个关键字key,key可以是对象本身,也可以是对象的一部分(如对象的某一个属性)
哈希码(hash code)—— 要将对象存储到HashTable,就需要将其关键字key映射到一个整型数据,称为key的哈希码(hash code)
哈希函数(hash function)——返回对象的哈希码
项(item)—— 哈希表中的每一项都有两个域:关键字域key及值域value(即存储的对象)。key及value都可以是任意的Object类型的对象,但不能为空(null),HashTable中的所有关键字都是唯一的
装填因子(load factor)—— (表中填入的项数)/(表的容量)
Hashtable( ); // 初始容量为101,最大装填因子为0.75 Hashtable(int capacity); Hashtable(int capacity, float maxLoadFactor);
Object put(Object key, Object value) —— 值value以key为其关键字加入到哈希表中,如果此关键字在表中不存在,则返回null,否则表中存储的value
Object get(Object key) —— 返回关键字为key的值value,如果不存在,则返回null。如
Object remove(Object key) —— 将键/值对从表中去除,并返回从表中去除的值,如果不存在,则返回null。如
boolean isEmpty() —— 判断哈希表是否为空 boolean containsKey(Object key) —— 判断给定的关键字是否在哈希表中 boolean contains(Object value) —— 判断给定的值是否在哈希表中 boolean containsValue(Object value) —— 判断给定的值是否在哈希表中 void clear() —— 将哈希表清空 Enumeration elements() —— 返回包含值的Enumeration对象 Enumeration keys() —— 返回包含关键字的Enumeration对象
HashMap类与HashTable类很相似,只是HashTable类不允许有空的关键字,而HashMap类允许
Set接口以及实现类
Set是最简单的集合,集合中的对象不按照特定的方式排序,并且没有重复的对象。Set接口主要有两个实现类:HashSet和TreeSet
Set集合里多个对象之间没有明显的顺序,基本与Collection方法相同。只是行为不同(Set不允许包含重复元素)。Set集合不允许重复 元素,是因为Set判断两个对象相同不是使用==运算符,而是根据equals方法。即两个对象用equals方法比较返回true
public class TestSet { public static void main(String[] args) { Set<String> books = new HashSet<String>(); //添加一个字符串对象 books.add(new String("Struts2权威指南")); //再次添加一个字符串对象, //因为两个字符串对象通过equals方法比较相等,所以添加失败,返回false boolean result = books.add(new String("Struts2权威指南")); System.out.println(result); //下面输出看到集合只有一个元素 System.out.println(books); } }
程序运行结果:
false
[Struts2权威指南]
说明:程序中,book集合两次添加的字符串对象明显不是一个对象(程序通过new关键字来创建字符串对象),当使用==运算符判断返回 false,使用equals方法比较返回true,所以不能添加到Set集合中,最后只能输出一个元素。Set接口中的知识,同时也适用于 HashSet、TreeSet和EnumSet三个实现类。
HashSet类
HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
HashSet的特点:
(1)HashSet不是同步的,多个线程访问是需要通过代码保证同步
(2)集合元素值可以使null。
HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
//类A的equals方法总是返回true,但没有重写其hashCode()方法 class A { public boolean equals(Object obj) { return true; } } //类B的hashCode()方法总是返回1,但没有重写其equals()方法 class B { public int hashCode() { return 1; } } //类C的hashCode()方法总是返回2,但没有重写其equals()方法 class C { public int hashCode() { return 2; } public boolean equals(Object obj) { return true; } } public class TestHashSet { public static void main(String[] args) { HashSet<Object> books = new HashSet<Object>(); //分别向books集合中添加2个A对象,2个B对象,2个C对象 books.add(new A()); books.add(new A()); books.add(new B()); books.add(new B()); books.add(new C()); books.add(new C()); System.out.println(books); } }
程序运行结果:
[B@1, B@1, C@2, A@b5dac4, A@9945ce]
TreeSet类
TreeSet是SortedSet接口的唯一实现,TreeSet可以确保集合元素处于排序状态(元素是有序的)。
TreeSet提供的几个额外方法:
Comparator comparttor(): 返回当前Set使用的Compara投入,或者返回null,表示以自然方式排序。
Object first():返回集合中的第一个元素。
Object last():返回集合中的最后一个元素。
Objiect lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元素可以不是TreeSet的元素)。
Object higher(Object e):返回集合中位于指定元素之后的元素(即大于指定元素的最小元素,参考元素可以不需要TreeSet的元素)。
SortedSet subSet(fromElement, toElement):返回此Set的子集,范围从fromElement(包含大于等于)到toElement(不包含小于)。
SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成。
SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。
public class TestTreeSetCommon { public static void main(String[] args) { TreeSet<Integer> nums = new TreeSet<Integer>(); //向TreeSet中添加四个Integer对象 nums.add(5); nums.add(2); nums.add(10); nums.add(-9); //输出集合元素,看到集合元素已经处于排序状态 System.out.println(nums); //输出集合里的第一个元素 System.out.println(nums.first()); //输出集合里的最后一个元素 System.out.println(nums.last()); //返回小于4的子集,不包含4 System.out.println(nums.headSet(4)); //返回大于5的子集,如果Set中包含5,子集中还包含5 System.out.println(nums.tailSet(5)); //返回大于等于-3,小于4的子集。 System.out.println(nums.subSet(-3 , 4)); } }
说明:由运行结果可以看出,TreeSet并不是根据元素的插入顺序进行排序,而是根据元素实际值来进行排序。TreeSet采用红黑树的数据结构对元素进行排序,具体排序内容会在后续文章中说明。