----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
集合(下)
1、迭代(iterator):迭代是取出collection集合中元素的方式(for循环、增强for循环、迭代器)。
for循环遍历:删除元素时集合后面的元素会向前移动,删除后循环变量要--
增强for循环:for(类型 变量名;容器){循环体},每次循环变量指向不同容器中元素
不能改变容器的结构。
Iterable接口:JDK1.5新定义作为Collection的父接口,因为Collection有iterator(),所以每一个子类集合对象
都具备迭代器(内部类),直接访问集合内部元素,主要为了实现增强for循环.
collection c = new ArrayList();
for(Interator it = c.iterator();it.hasNext()){
System.out.println(it.next());
}
另一种方式:
Iterator it = c.iterator(); //通过对象的iterator()获得迭代器Iterator
while(it.hasNext()) { //通过迭代器的hasNext()判断是否存在下一个元素
System.out.println(it.next()); //通过迭代器的next()获取下一个元素
}
迭代注意事项:
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
为什么next方法的返回类型是Object的呢?
集合是存储对象的容器,而对象可以是任意类型的,所以next()获取的元素都会自动强转为Object类型
如果指定了集合的类型,在获取元素时必须要强转为定义的类型。
迭代出现的问题:
Iterator it = list.iterator();
while(it.hasNext()){
String s = (String)it.next();
if(s.equals("abc2"))
list.add("haha");//此处出现并发修改异常:ConcurrentModificationException
System.out.println("s="+s);
}
System.out.println(list);
Iterator里面没有add(),
原因:迭代器Iterator中只有三个操作,判断hasNext(),获取next(),删除remove()。想要其它的操作时,
比如添加,iterator就不可以使用了。该例用容器list当中的add()添加元素,所以出现了异常。
解决:要么只使用集合的方法操作元素,要么只使用迭代器的方法操作元素,不能同时使用。
对于List集合,有一个新的迭代方式:ListIterator(列表迭代器),它是Iterator的子接口,
提供了更多迭代过程中对元素的操作:
List list = new ArrayList();
ListIterator li = list.listIterator();
li.add(E e) //将指定的元素插入列表
li.set(E e) //用指定元素替换next 或 previous 返回的最后一个元素
boolean li.hasNext() //是否有下一个
boolean li.hasPrevious()//是否有前一个
li.next() //返回下一个元素
li.previous() //返回前一个元素
2、Map集合:
Map集合的特点:
Map与Collection在集合框架中属并列存在。
Map存储的是键值对
Map存储元素使用put方法,Collection使用add方法。
Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素。
Map集合中键要保证唯一性。
Map集合的常用方法:
添加:put(key,value): 如果存入已有的键,会发生值覆盖的情况。
判断:containsKey(key),containsValue(value);
取出:get(key);
删除:remove(key);
个数:size();
取出所有值:values();
Map集合的两种遍历方式:
原理:将Map集合转成Set集合。在通过迭代器取出。
keySet():返回一个由Map集合中的所有键组成的Set集合,再使用Map集合的get()取出键所对应的值。
entrySet():将Map集合中的键值映射关系封装成Map.Entry对象,并存入到Set集合中。迭代该集合取出
Map.Entry对象,并通过该对象的getKey(),getValue()方法取出map集合中的键和值。
Map集合的子类:
|--TreeMap:对键进行排序,排序原理与TreeSet相同。通过二叉树算法保证键唯一性
|--HashMap:线程不安全,速度快,允许存放null键,null值。通过HashSet原理保证键唯一性
当HashMap返回为null时,有两种情况:该键不存在,或该键存在对应的值是null。
|--LinkedHashMap:是HashMap的子类, 原理相同,但是可以保留存储顺序
|--Hashtable:线程安全,速度慢,不允许存放null键,null值,已被HashMap替代。
|--Properties:
Hashtable的子类,所以也是线程安全的。通常用来操作配置文件,一般配置项等号两边都是String,
所以该集合中的两列保存的都是String类型的数据。这个集合中只能存String,所以不需要定义泛型。
是一个可以集合和流相结合的容器。
特有方法:
list(PrintStream):列出集合中的数据。
load(InputStream):将输入流关联的文件中的数据加载进集合。
store(OutputStream,String):将集合的数据存储到输出流所关联的文件中。
setProperties(key,value):只是在内存中修改了配置属性
什么时候使用Map集合?
当分析问题时,对象间出现了映射关系时,就要先想到Map集合。
例:获取字符串中每一个字母出现的次数。要求结果是:a(3)b(1)....;
public String getCharCount(String str) {
char[] chs = str.toCharArray(); //将传入的字符参数转换成字符数组
int count = 0; //定义计数器
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();//定义TreeMap集合存储元素
for(int x=0; x<chs.length; x++) { //从0角标遍历字符数组,角标上的元素是集合中的键
if(!(chs[x]>='a' && chs[x]<='z'))//如果角标上的键不再a~z之间
continue; //结束本次循环,开始下次循环
Integer i = tm.get(chs[x]); //满足条件,通过集合get(key)方法获取对应的值i
if(i!=null) //值不为空,这个值就是该字符的次数
count = i;
count++; //为空,计数器+1表示该字符出现一次
tm.put(chs[x],count); //put(key,value)方法,将字符和对应的次数添加到集合中
}
StringBuilder sb = new StringBuilder();//定义缓冲区StringBuffer sb
Iterator<Map.Entry<Character,Integer>> it = tm.entrySet().iterator();
while(it.hasNext()) { //获取迭代器,定义泛型,类型为Entry:键值对映射关系
Map.Entry<Character,Integer> me = it.next();//获取集合中的Entry
Character ch = me.getKey(); //再通过Entry的getKey()方法,获取键
Integer x = me.getValue(); //getValue()方法获取值
sb.append(ch+"("+x+")"); //append()方法将键和值添加到缓冲区中
}
return sb.toString(); //toString()将sb中的元素转成字符串,并返回给函数
}