集合类
数组可以用于保存多个对象,但是如果在对象数目无法确定的情况下,数组是不适用的,因为数组的长度不可变.为了保存这些数目不确定的对象,JDK中提供了集合类(又称容器类,),这些类可以存储任意类型的对象,并且长度可变.所有的集合类都位于Java.util包中,在使用时需要导入该报,否则会出现异常.
集合按照存储结构可以分为两大类,分别是单列集合(Collection) 和双列集合(Map) 这两种集合的特点如下所示.
Collection:单列集合的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List 和Set .其中,List的特点是元素有序,元素可重复; Set的特点是元素无序,而且不可重复.List接口的主要实现类有:ArrayList 和LinkedList ..Set接口的主要实现类有HashSet和TreeSet.
Map: 双列集合类的根接口,用于存储具有键(Key)、值(Value)映射关系的元素,每个元素都包含一对键值,在使用Map集合时可以通过指定的Key找到对应的Value。Map接口主要实现类有HashMap 和TreeMap
Collection 接口简介:
Collection是所有单列集合的父接口,因此Collection接口中定义了很多单列集合(List和Set)通用的方法,这些方法分别用于在集合中添加元素、删除元素、获取集合中元素的个数等,具体如下:
方法声明 | 功能描述 |
boolean add (Object o) | 向集合中添加一个元素 |
boolean addAll(Collection c) | 将指定Collection中的所有元素添加到该集合中 |
void clear() | 删除该集合中的所有元素 |
boolean remove(Object o) | 删除该集合中的指定元素 |
boolean removeAll(Collection c) | 删除指定集合中的所有元素 |
boolean isEmpty() | 判断该集合是否为空 |
boolean cotains(Object o) | 判断该集合是否包含某个元素 |
boolean containsAll(Collection c) | 判断该集合中是否包含指定集合中的所有元素 |
Iterator iterator() | 返回在该集合的元素上进行迭代的迭代器(iterator)用于遍历该集合所有元素 |
int size() | 获取该集合元素的个数 |
List 接口 (可重复/线性方式存储 元素有序 )
方法声明 | 功能描述 |
void add(int index,Object element) | 将元素element插入到List集合的index处 |
boolean addAll(int index,Collection c) | 将集合c所包含的所有元素插入到List集合的index处 |
Object get(int index) | 返回集合索引index处的元素 |
Object remove(int index) | 删除index索引处的元素 |
Object set(int index,Object element) | 将索引Index处的元素替换成element对象,并将替换后的元素返回 |
int indexOf(Object o) | 返回对象o在List集合中出现的位置索引 |
int lastIndexOf(Object o) | 返回对象o在List集合中最后一次出现的位置索引 |
List subList(int fromIndex,int toIndex) | 返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合 |
ArrayList 集合 最常用的集合类
在ArrayList内部封装了一个长度可变的数组,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组.
ArrayList集合中大多数的方法都是从父接口Collection和List继承的,其中add()方法和get()方法用于实现元素的存取.
ArrayList list=new ArrayList();
list.add("stw");
list.add("stw");
list.add("hj");
list.add("321");
list.add(2, "s");
System.out.println(list.size());
System.out.println(list.toString());
System.out.println(list.indexOf("stw"));
list.remove("stw");
System.out.println(list);
5
[stw, stw, s, hj, 321]
0
[stw, s, hj, 321]
由于ArrayList集合的底层使用一个数组保存元素,在增加或删除指定位置的元素时,会导致创建新的数组,极大地降低了效率,因此该集合不适合进行大量的增删操作,但是这种数组的结构允许通过索引的方式返回元素,因此ArrayList集合的优势是查找元素效率高.
Iterator接口
在使用集合类时,一定会遇到需要遍历所有元素的情况,为此,JDK中专门提供了一个接口Iterator.Iterator接口也是集合框架中的一员,它与Collection和Map接口不同的是,Collection接口与Map接口主要用于存储元素,而Iterator主要用于遍历Collection和其子类中的元素,因此Iterator对象也被称为迭代器.
Iterator iterator=list.iterator();
while(iterator.hasNext())
{
Object object=iterator.next();
System.out.println(object);
}
在使用Iterator遍历集合的整个过程中,首先通过调用ArrayList集合的iterator() 方法获得迭代器对象,然后使用hasNext()方法判断该集合中是否存在下一个元素,如果存在,则调用next方法将元素取出;如果不存在则跳出while循环
foreach循环
虽然Iterator 可以用于遍历集合中的元素,但是在写法上比较麻烦,为了能够简化书写,从JDK5.0开始,Java提供可foreach循环.foreach循环是一种更加简洁的for循环,也称作增强for循环,foreach循环用于遍历集合或数组中的元素,具体语法格式如下:
for (集合内储存类型 变量名 : 集合的变量名)
{
执行语句部分
}
从上面的格式可以看出,与普通for循环ixangbi,foreach循环在遍历集合时,不需要知道集合的长度,也无须知道索引,foreach能自动遍历集合中的每个元素.
for (Object o : list) {
System.out.println(o);
}
foreach循环与普通的for循环遍历有所不同,foreach循环没有循环条件,也没有迭代语句,所有的这些工作都交给JVM执行.foreach循环的次数由集合中元素的个数决定,每次循环时,foreach中都需要变量将当时循环的元素记住,从而将集合中的元素分别输出.
泛型
通过前面的学习,读者已经了解到集合可以存储任何类型的对象,但是存储一个对象到集合中后,集合会"忘记"这个对象的类型,当该对象从集合中取出时,这个对象的编译类型就变成了Object类型.那么在取出元素时,如果进行强制类型转换就很容易抛出异常.为了解决这个问题,Java引入了"参数化类型(parameterized type)"这个概念,即泛型,它可以限定方法操作的数据类型,在定义集合类时,使用"<参数化类型>"的方式指定该类中方法操作的数据类型,格式:
ArrayList <参数化类型> list =new ArrayList <参数化类型>();
ArrayList <String>list=new ArrayList<String>();
这种方法限定了ArrayList集合只能存储String 类型元素,改写后的程序在Eclipse中编译会出错;
需要注意的是,在使用泛型后,每次遍历集合元素时,可以指定元素类型为String,而不是为Object,这样就避免了在程序中进行强制类型转换.
ArrayList <String>list=new ArrayList<String>();
for (String o : list) {
System.out.println(o);}
Set 接口
Set接口和List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了.与List接口不同的是,Set接口中的元素无序,并且都会以某种规则保证存入的元素不会出现重复.
Set接口主要有两个实现类分别是HashSet和TreeSet.其中,HashSet是根据对象的哈希值确定元素在集合中的存储位置,因此具有良好的存取和查找性能.TreeSet则是以二叉树的方式存储元素,它可以实现对集合中的元素进行排序.
HashSet 集合
HashSet是Set接口中的一个实现类,HashSet按Hash算法存储集合中的元素,因此具有很好的存取和查找性能,并且存储的元素是无序和不可重复的.
HashSet ha=new HashSet();
ha.add("123");
ha.add("456");
ha.add("789");
ha.add("123");
for (Object o:ha)
{
System.out.println(o);
}
123
456
789
HashSet集合之所以能确保不出现重复的元素,是因为在向Set中添加对象时,会先调用此对象所在类的hashCode()方法,计算此对象的哈希值,此哈希值决定了此对象在Set中的存储位置.若此位置之前没有对象存储,则将这个对象直接存储到此位置.若此位置已有对象存储,再通过equals()比较这两个对象是否相同,如果相同,则后一个对象就不能再添加进来.
Map接口
Map集合是一种双列集合,集合中的每个元素都包含一个键对象Key和一个值对象Value,键和值是一一对应的关系,称为映射.也就是说,根据键就能找到对应的值,类似于生活中一张身份证对应一个人一样.为了便于对Map集合的操作,Map集合中提供了很多方法.
方法声明 | 功能描述 |
void add(int index,Object element) | 将元素element插入到List集合的Index处 |
boolean addAll(int index,Collection c) | 将集合c所包含的所有元素插入到List集合的index处 |
Object get(int index) | 返回集合索引index处的元素 |
Object remove (int index) | 删除index索引处的元素 |
Object set(int index,Object element) | 将索引index处的元素替换成element对象,并将替换后的元素返回 |
int indexOf(Object o) | 返回对象o在List集合中出现的位置索引 |
int lastIndexOf(Object o) | 返回对象o在List集合中最后一次出现的位置索引 |
List subList(int fromIndex,int toIndex) | 返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合 |
HashMap集合是基于哈希表的Map接口的实现,它用于存储键值映射关系,但不保证映射的顺序.下面通过案例演示先遍历Map集合中所有的键,再根据获取相应的值的方式.
HashMap hashMap=new HashMap();
hashMap.put("001", "stw");
hashMap.put("002", "hj");
hashMap.put("003", "lyx");
hashMap.put("004", "wfl");
hashMap.put("001", "sss");
System.out.println(hashMap);
Set keySet=hashMap.keySet();
for (Object o:keySet)
{
System.out.println(o+" "+hashMap.get(o));
}
Iterator iterator=keySet.iterator();
while (iterator.hasNext())
{
Object key=iterator.next();
Object value =hashMap.get(key);
System.out.println(key+"="+value);
}
}
首先调用HashMap集合的KeySet()方法,获得存储Map中所有键的Set集合,然后通过Iterator迭代Set集合的每一个元素,即每一个键,最后通过调用get(String key)方法,根据键获取对应的值.
Map集合的另外一种遍历方式是先获取集合中的所有映射关系,然后从映射关系中取出键和值.
HashMap hashMap=new HashMap();
hashMap.put("001", "stw");
hashMap.put("002", "hj");
hashMap.put("003", "lyx");
hashMap.put("004", "wfl");
hashMap.put("001", "sss");
System.out.println(hashMap);
Set entrySet=hashMap.entrySet();
for (Object en:entrySet)
{
Map.Entry entry=(Map.Entry)en;
Object key=entry.getKey();
Object value=entry.getValue();
System.out.println(key+" "+value );
}
System.out.println(entrySet);
Iterator iterator=entrySet.iterator();
while (iterator.hasNext())
{
Map.Entry entry=(Map.Entry) iterator.next();
Object key=entry.getKey();
Object value=entry.getValue();
System.out.println(key+" "+value);
}
}
首先调用Map对象的entrySet()方法获得存储在Map中所有映射的Set集合,这个集合中存放了Map.Entry类型的元素(Entry是Map内部接口),每一个Map.Entry对象代表Map中的一个键值对,然后迭代Set集合,获得每一个映射对象,并分别调用映射对象的getKey()和getValue()方法获取键和值.
Properties集合
Properties主要用于存储字符串类型的键和值,由于Properties类实现了Map接口,因此,Properties类本质上是一种简单的Map集合.实际开发中,经常使用Properties集合存取应用的配置项.假设有一个文本编辑工具,要求文本的字体为微软雅黑,字号为20px,字体颜色为green,其配置项应该如下所示:
face=微软雅黑
size=20px
color=green
在程序中可以使用Properties集合 对这些配置项进行存取,下面通过案例学习Properties集合
Properties properties=new Properties();
properties.setProperty("face", "微软雅黑");
properties.setProperty("size", "20px");
properties.setProperty("color", "green");
Set<String> names=properties.stringPropertyNames();
for (String key :names)
{
String value=properties.getProperty(key);
System.out.println(key +" "+value);
}
在Properties类中,针对字符串的存取提供了两个专有的方法:setProperty()和getProperty().其中,setProperty()方法用于将配置项的键和值添加到 Properties集合中,getProperty()方法用于根据键获取对应的值.在第十行代码中调用Properties的stringPropertyNames()方法得到一个所有键的Set<String>集合,然后遍历所有的键时,通过调用getProperty()方法获得键所对应的值.