JAVA常用集合框架用法详解——基础篇
2015-04-21 10:43
891 查看
下面举几个例子主要是引出集合类的:
1、8,4,5,6,7,55,7,8 像这样的类型相同的可以使用数组来存储,本例可以用int[] arr来存储。
2、”zhnagsan”,true,68 像这样的可以使用StringBuilder或者StringBuffer来存储,但最终需要使用.toString()的方法转换成字符串才可以使用。即变为:”zhnagsantrue68”。
3、”李思”,25 像这样的可以使用对象来存储,如: new Person(“李思”,25);
9.1那什么时候需要使用集合类呢??????
1.集合类的由来:
对象用来封装特有的数据,对象多了需要存储,或者对象的个数不确定,就使用集合容器进行存储。
2.集合的特点:
--用于存储对象的容器
--集合的长度是可变的
--集合中不可以存储基本的数据类型(如:int、 char、 boolean之类的)
接下来用一幅图演示集合的整体框架:
![](http://img.blog.csdn.net/20150421104802839?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTFVMRUkxMjE3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
3、集合容器因内部的数据结构不同,有多种具体容器。不断向上抽取,就形成了集合框架。
框架的顶层Collection接口:
Collection的常见方法:
---添加。
boolean add(Object obj); boolean addAll(Collectioncoll);
---删除
boolean remove(Object obj); boolean removeAll(Collection coll);
void clear();//将集合中的元素清空
代码如下:
---判断
boolean contains(Object obj);//是否包含
boolean containsAll(Collection coll);
boolean isEmpty();//判断集合中是否含有元素
---获取
int size();//获取集合中元素的个数
Iterator iterator();//取出元素的方式,使用的是迭代器
Object get(int i);
代码如下:
代码如下:测试Iterator的用法
----其他
boolean retainAll(Collectioncoll);//取交集
Object[] toArray();将集合转成数组
4、Collection是接口,只能通过子类来实例化。如:Collection coll=new ArrayList();
注意:这里会稍微提一下之前的迭代输出的代码。迭代输出有两种写法,如下:
法一:
Iterator it=coll.iterator();
while(it.hasnext){
system.out.println(it.next());
}
法二:
for(Iterator it=coll.iterator;it.hasnext();){
system.out.println(it.next());
}
比较两种方法,我们会注意到while()循环结束后,it会一直占着内存不放,而for循环不会出现这种情况。
5、迭代器的原理
迭代器,取出元素的对象,该对象必须依赖具体的容器。因为每一个容器的数据结构是不同的。所以该迭代器是在容器中进行内部的实现。对于使用容器而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可。也就是iterator方法。
Iterator接口就是对所有Collection容器进行元素取出的公共接口。
9.2、Collection的子接口
----List:有序(存入和取出的顺序一致),元素都有索引(即角标),元素可以重复。
-----Set:元素不能重复,无序的。
一、List特有的常见方法(都有一个共性的特点就是可以操作角标)
List集合是可以完成对元素的增删改查,List集合的实现是通过子类来完成:
如 List ll=new ArrayList();
1、添加(通过索引的位置来添加元素)
voidadd(index,element);
voidadd(index,Collection)
//List特有的取出方式之一
for(inti=0;i<ll.size();i++){
System.out.println(ll.get(i));
}
2、删除(删除相应索引位置的元素)
Object remove(index);//返回被删除的元素
3、修改(修改指定索引位置的元素,并返回修改前的元素)
ObjectSet(index,element)//返回被修改的元素
4、获取:
Object get (index);
int IndexOf(object);//返回此列表中第一次出现指定元素的索引,如果此列表不包含该素, //则返回-1.
int lastIndexOf(object);//返回此列表中最后一次出现指定的元素,如果此列表不包含该元素, //则返回-1.
List subList(int from,int to);//包含头,不包含尾,获取子列表。
接下来我们看看一个使用迭代器出错的代码:
主要代码如下:
ll.add(“qwe1”);
ll.add(“qwe2”);
ll.add(“qwe3”);
Iterator it=ll.iterator();//获取List集合的迭代器的对象
while(it.hasnext()){
Object obj=it.next();
if(obj.equals(“qwe2”)){
ll.add(“abc9”);//集合添加元素
}
else{
System.out.println(“next:”+obj);//打印元素
}
}
以上就是一段代码,但是在运行while循环中会出现异常:Java.util.concurrentModificationException。主要的原因是:在迭代器过程中,不要使用集合来操作元素,容易抛出异常。怎么解决呢???我们可以使用Iterator的子接口ListIterator来完成在迭代器中对元素进行更多的操作。
更换代码如下:
ll.add(“qwe1”);
ll.add(“qwe2”);
ll.add(“qwe3”);
ListIterator it=ll.listiterator();//获取List集合的迭代器的对象
while(it.hasnext()){
Object obj=it.next();
if(obj.equals(“qwe2”)){
it.add(“abc9”);//迭代器对象进行添加元素
}
else{
System.out.println(“next:”+obj);//打印元素
}
}
二、List的子类
-------Vector:内部是数组数据结构,是同步的(即线程安全的)。增删修改查询都很慢。(不常用)
-------ArrayList:内部是数组数据结构的,是不同步的。替代了Vector,查询的速度快。
------LinkedList:内部是链表的数据结构,是不同步的。增删元素的速度非常快。
这里我们做一个练习:使用LinkedList来模拟一个堆栈和队列的数据结构。
堆栈:先进后出(First In Last Out)FILO
队列:先进先出(First In First Out)FIFO
我们应该描述这样一个容器,给使用者提供一个容器对象完成这两种结构的一种。
LinkedList(可以实现队列和堆栈的功能)
常用的方法如下:
addFirst();
addLast();//从jdk1.6后改成 offerFirst(),和offerLast();
getFirst();//获取但不移除,如果链表为空。抛出NoSuchElementException
getLast();
从jdk1.6后上面两个改成:
peekFirst();//获取但不移除,如果链表为空,则返回null
peekLast();
removeFirst();//获取,且移除当前的元素。如果链表为空。抛出NoSuchElementException
removeLast();
从jdk1.6后上面两个改成:
poolFirst();//获取且移除当前的元素,如果链表为空,则返回null
poolLast();
代码的实现如下:
运行结果如下:
实现堆栈的功能
111已经加入堆栈
222已经加入堆栈
333已经加入堆栈
444已经加入堆栈
444已经退出堆栈
333已经退出堆栈
222已经退出堆栈
111已经退出堆栈
实现队列的功能
111已经加入队列
222已经加入队列
333已经加入队列
444已经加入队列
111已经出队列
222已经出队列
333已经出队列
444已经出队列
三、ArrayList集合存数自定义对象
1、集合里存储的都是对象的引用,迭代器里迭代的也是集合中的引用
代码如下:
四、Set集合
Set是个接口,元素不可以重复,是无序的。Set接口中的方法和Collection的一致。
Set的子类:
1、-----HashSet:此类实现的Set接口,由哈希表(实际上是一个HashMap)实例支持,它不保证Set的迭代顺序,但是允许使用null元素。
HashSet:内部结构是哈希表,是不同步的。
哈希表确定元素是否相同:
一、 判断的是两个元素的哈希值是否相同。如果相同,再判断两个对象的内容是否相同。
二、 判断哈希值是否相同,其实判断的是对象的hashCode()的方法。判断内容是否相同,用的是equals()方法。
三、 如果哈希值不同,那就不需要进行equals判断。
HashSet集合数据结构是哈希表,所以存储元素的时候,使用元素的hashCode()方法来确定位置,如果位置相同,再通过元素的equals方法来确定是否相同。
练习题:定义功能去除ArrayList的重复元素
注意:像ArrayList集合,在判断元素是否相同的时候,仅仅需要判断equals()方法。因为数据结构不同,对元素的判断依据也就一样。
代码如下:
运行结果如下(由于无序这只是一种可能):
lisi4---24
lisi3---23
lisi2---22
lisi1---21
特别注意:如果希望元素不重复,但是要有序,这时可以考虑使用LinkedHashSet,它是HashSet的子接口。
2、----TreeSet:可以对Set集合的元素进行排序,不是同步的。
判断元素唯一性的方式就是根据比较方法compareTo()的返回结果,判断返回的结果是否为0,是0就表示相同的元素且不存储。否则就相反
TreeSet对元素进行排序的方式一:让元素具备比较功能,元素需要实现comparable接口,覆盖CompareTo()方法。
如果不要按照对象具备的自然顺序进行排序,如果对象不具备自然顺序。(即对象没有比较性,或者具备的比较性不是我们所需要的)这个时候怎么办???
TreeSet对元素进行排序的方式二:(生成一个比较器)让集合自身具备比较的功能,定义一个类,实现Comparator接口,覆盖compare方法,将该类的对象作为参数传递给TreeSet集合的构造函数。
代码演示如下:
运行结果如下:
测试实现Comparable接口的比较功能(以年龄大小)
zhangsan....22
zhaoliu....24
wangwu....25
zhouqi....25
lisi....26
wuba....28
测试实现Comparator接口,作为一个比较器来进行比较的功能(以名字的字典顺序)
lisi....26
wangwu....25
wuba....28
zhangsan....22
zhaoliu....24
zhouqi....25
练习:TreeSet集合练习,字符串长度的排序
分析:Java代码中。TreeSet默认的会为字符串进行字典顺序大小的排序,但这不符合我们的要求。这个时候怎么办,我们必须要用到比较器。即comparator接口来实现。
具体代码实现如下:
运行结果如下:
t
as
dds
fghf
asdfdf
fdsfsg
总结:List: 1---ArrayList 2---LinkedList
Set 1---HashSet --LinkedHashSet
2---TreeSet
注意,后缀名就是该集合所属的体系,前缀名就是该集合的数据结构。
看到array:就要想到数组,就要想到查询快,有角标。如果不希望出现重复的元素则需要覆盖equals()方法。
看到link就要想到链表,就要想到增删快,就要想到add,get,remove+first(last)的方法。
看到hash就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashCode()和equals()方法。
看到tree就要想到二叉树,就要想到排序,就要想到两个接口:comparator和comparable。
并且通常这些常用的容器都是不同步的。
五、Map集合
Map<K,V>;一次添加一对元素。而Collection一次添加一个元素。Map集合也称为双列集合,Collection集合也称为单列集合。其实Map集合中存储的就是键值对,且保证键(K)的唯一性。
常用的方法:
1、添加
value put(key,value);//返回前一个与key关联的值,如果没有则返回null
2、删除
value remove(key);//根据指定的key删除这个键值对
void clear();//清除这个Map集合
3、判断
boolean containsKey(key);
boolean containsValue(value);
boolean isEmpty();//判断是否为空
4、获取
value get(key);//用过键来返回值,如果没值该键返回null。当然可以通过返回null来判断是否包含指 //定的键(K)
int size();//获取键值对的个数
Map接口是如何实例化的??
如:Map<Integer,String> map=newHashMap<Integer,String>();//实例化一个 //HashMap对象
5、注意:问题:如何获取map中的所有的元素???
取出map中的元素,原理如下:通过keySet方法获取map中所有键所在的Set集合中,再通过Set的迭代器获取到每个键。然后对每个键通过map集合的get()方法获取其所对应的值。
![](http://img.blog.csdn.net/20150421112140225)
代码演示如下:
运行结果如下:
此时给相同的key赋键值,返回的上一个键值是:null
此时给相同的key赋键值,返回的上一个键值是:wangcai
所有的键值对如下:{2=lisi,6=pp, 7=ll, 8=wq}
获取相应的key值得键值:ll
获取相应的key值得键值:null
删除key为6的键值后的map{2=lisi, 7=ll, 8=wq}
使用迭代获取的元素:lisi
使用迭代获取的元素:pp
使用迭代获取的元素:ll
使用迭代获取的元素:wq
上面提到的只是一种方法,另一种方法是entrySet()。该方法将键与值得映射关系作为对象存储到了Set集合中,而这个映射关系的类型就是Map.EntryKey类型。(打个比方:键是丈夫,值就是妻子,映射关系就是结婚证)。
Entry本身就是一个嵌套的静态接口。
图解如下:
![](http://img.blog.csdn.net/20150421112328068)
6、values方法(如果只想获取值不要键怎么办???)
Collection<V> values()方法:返回映射关系中包含的值得Collection集合。注意只含值,然后利用Iterator迭代器来迭代即可获取所有的值。
7、Map常用的子类
--Hashtable:内部结构是哈希表,是同步的。不支持null作为键和值。
---Properties:Hashtable的子类,用来存储键值对配置文件的信息, 可以和IO口技术向结合。
--HashMap:内部结构是哈希表,不是同步的,支持null作为键和值。
--TreeMap:内部结构是二叉树,不是同步的,支持null作为键和值。
代码演示如下:
运行代码如下:
xiaoqiang..18....后海
wangwu..32....天津
zhangsan..44....北京
lisi..24....南京
运行结果:
lisi..24....南京
wangwu..32....天津
xiaoqiang..18....上海
xiaoqiang..28....后海
zhangsan..44....北京
相信以上的代码能够帮助我们更好地理解Map的子类。以及获取所有子类元素的方法:keySet()和EntrySet()两种方法。接下来看看练习:
练习题:” aFGDHRTYdshgfd./,/g1uAAD898 styefbhbhad”,这样一个随机的字符串。获取该字符串中每个字符出现的次数。并最终以a(n),b(m)……这样的格式打印出来。
分析如下:对于结构的显示,字符和出现次数之间存在着映射的关系。而且这种关系很多。既然很多我们就需要存储,但是能存储映射关系的有数组和Map集合。这时我们需要考虑:关系一方有序号编码吗?答案是没有,于是我们就选用Map集合,同时又发现可以保证唯一性的一方具备着顺序如:a,b,c,d,……。所以最后的选择是TreeMap集合。
操作思路:这个集合最后存储的是字符与次数的对应关系。
1、因为操作的是字符串中的字符,所以先将字符串变成字符数组。
2、遍历字符数组,用每一个字符作为键去查询Map集合这个表。
3、如果该键不存在,就将该字母作为键,1作为值,存储到Map集合中。
4、如果该键存在,就将该字符键对应的值加1,在将该字母与加1后的值存在Map集合中。键相同,只会覆盖,这样就记录了字符的次数。
5、遍历字符数组结束后,Map集合就记录了所有的字符出现的次数。一次迭代输出即可是实现。
代码实现如下:
运行结果如下:
A(2)D(2)F(1)G(1)H(1)R(1)T(1)Y(1)a(2)b(2)d(3)e(1)f(2)g(2)h(3)s(2)t(1)u(1)y(1)
补充:接下来补充一个Collection.Sort()方法的实例:可以看看代码:
运行结果如下:
57已经成功添加
22已经成功添加
65已经成功添加
52已经成功添加
27已经成功添加
90已经成功添加
38已经成功添加
77已经成功添加
47已经成功添加
21已经成功添加
-----排序前------
元素:57
元素:22
元素:65
元素:52
元素:27
元素:90
元素:38
元素:77
元素:47
元素:21
--------排序后--------
元素:21
元素:22
元素:27
元素:38
元素:47
元素:52
元素:57
元素:65
元素:77
元素:90
====排序前=====
Zj
gkjvUfLB
WgPiL3VX
Xj2DtAtL9
kyrkT9ILYa
G
s0FfBD
bZR
eDA
pVihS
====排序后=====
G
WgPiL3VX
Xj2DtAtL9
Zj
bZR
eDA
gkjvUfLB
kyrkT9ILYa
pVihS
s0FfBD
=====排序前====
319.tim
606.jack
464.lucy
100000.lily
=====排序后====
100000.lily
319.tim
464.lucy
606.jack
-------按照名字进行排序---------
=====排序后====
606.jack
100000.lily
464.lucy
319.tim
XXiaoLEI整理于2015-04-06 。
1、8,4,5,6,7,55,7,8 像这样的类型相同的可以使用数组来存储,本例可以用int[] arr来存储。
2、”zhnagsan”,true,68 像这样的可以使用StringBuilder或者StringBuffer来存储,但最终需要使用.toString()的方法转换成字符串才可以使用。即变为:”zhnagsantrue68”。
3、”李思”,25 像这样的可以使用对象来存储,如: new Person(“李思”,25);
9.1那什么时候需要使用集合类呢??????
1.集合类的由来:
对象用来封装特有的数据,对象多了需要存储,或者对象的个数不确定,就使用集合容器进行存储。
2.集合的特点:
--用于存储对象的容器
--集合的长度是可变的
--集合中不可以存储基本的数据类型(如:int、 char、 boolean之类的)
接下来用一幅图演示集合的整体框架:
3、集合容器因内部的数据结构不同,有多种具体容器。不断向上抽取,就形成了集合框架。
框架的顶层Collection接口:
Collection的常见方法:
---添加。
boolean add(Object obj); boolean addAll(Collectioncoll);
</pre><pre name="code" class="html">代码如下: package com.ll.list; import java.util.ArrayList; import java.util.List; public class testAdd { public static void main(String[] args) { // TODO Auto-generated method stub List<String> allList=new ArrayList<String>();//定义List对象 List<String> list=new ArrayList<String>();//定义另一个List对象 allList.add("hello");//使用从Collection接口中继承的方法 allList.add(0, "world");//此方法为List自己扩展的方法 System.out.println(allList); list.add("LL"); list.add("www.ll.com"); allList.addAll(list);//增加一组对象,此方法是从父类继承的 System.out.println(allList); allList.addAll(1, list);//此方法是List接口自己扩展的方法 System.out.println(allList); } }
---删除
boolean remove(Object obj); boolean removeAll(Collection coll);
void clear();//将集合中的元素清空
代码如下:
package com.ll.list; import java.util.ArrayList; import java.util.List; public class testRemove { public static void main(String[] args) { // TODO Auto-generated method stub List<String> allList=new ArrayList<String>();//实例化一个List对象 allList.add("kello"); allList.add("joke"); allList.add("www.ll.com"); allList.add("world"); System.out.println(allList);//输出List对象中的元素 allList.remove(0);//删除指定位置的内容 System.out.println(allList); allList.remove("joke");//删除指定的内容 System.out.println(allList); } }
---判断
boolean contains(Object obj);//是否包含
boolean containsAll(Collection coll);
boolean isEmpty();//判断集合中是否含有元素
package com.ll.list; import java.util.ArrayList; import java.util.List; public class testSizeAndGet { public static void main(String[] args) { // TODO Auto-generated method stub List<String> allList=new ArrayList<String>();//定义并实例化List对象 allList.add("world"); allList.add("world"); allList.add("kkorld"); allList.add("pprld"); allList.add("lllrld"); allList.add("wqwld"); System.out.println("从前向后输出:"); for(int i=0;i<allList.size();i++){ System.out.println(allList.get(i)+".."); } System.out.println("从后向前输出:"); for(int i=allList.size()-1;i>=0;i--){ System.out.println(allList.get(i)+".."); } } }
---获取
int size();//获取集合中元素的个数
Iterator iterator();//取出元素的方式,使用的是迭代器
Object get(int i);
代码如下:
package com.ll.list; import java.util.ArrayList; import java.util.List; public class testSizeAndGet { public static void main(String[] args) { // TODO Auto-generated method stub List<String> allList=new ArrayList<String>();//定义并实例化List对象 allList.add("world"); allList.add("world"); allList.add("kkorld"); allList.add("pprld"); allList.add("lllrld"); allList.add("wqwld"); System.out.println("从前向后输出:"); for(int i=0;i<allList.size();i++){ System.out.println(allList.get(i)+".."); } System.out.println("从后向前输出:"); for(int i=allList.size()-1;i>=0;i--){ System.out.println(allList.get(i)+".."); } } }
代码如下:测试Iterator的用法
package com.ll.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /* * 迭代输出:Iterator * 是最常用的的集合输出操作 * 但是只能进行单向的从前向后输出 */ public class testIterator { public static void main(String[] args) { // TODO Auto-generated method stub List<String> allList=new ArrayList<String>(); allList.add("hello"); allList.add("world"); allList.add("__ll__"); //直接实例化一个Iterator接口 System.out.println("删除前的集合"+allList.toString()); Iterator<String> it=allList.iterator(); while(it.hasNext()){//判断是否还有元素 String str=it.next(); if("__ll__".equals(str)){ it.remove();//使用remove方法删除指定的元素 } else{ System.out.print(str+"、");//next()方法用来取出当前元素 } } System.out.println("\n删除后的集合"+allList.toString()); } }
----其他
boolean retainAll(Collectioncoll);//取交集
Object[] toArray();将集合转成数组
4、Collection是接口,只能通过子类来实例化。如:Collection coll=new ArrayList();
注意:这里会稍微提一下之前的迭代输出的代码。迭代输出有两种写法,如下:
法一:
Iterator it=coll.iterator();
while(it.hasnext){
system.out.println(it.next());
}
法二:
for(Iterator it=coll.iterator;it.hasnext();){
system.out.println(it.next());
}
比较两种方法,我们会注意到while()循环结束后,it会一直占着内存不放,而for循环不会出现这种情况。
5、迭代器的原理
迭代器,取出元素的对象,该对象必须依赖具体的容器。因为每一个容器的数据结构是不同的。所以该迭代器是在容器中进行内部的实现。对于使用容器而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可。也就是iterator方法。
Iterator接口就是对所有Collection容器进行元素取出的公共接口。
9.2、Collection的子接口
----List:有序(存入和取出的顺序一致),元素都有索引(即角标),元素可以重复。
-----Set:元素不能重复,无序的。
一、List特有的常见方法(都有一个共性的特点就是可以操作角标)
List集合是可以完成对元素的增删改查,List集合的实现是通过子类来完成:
如 List ll=new ArrayList();
1、添加(通过索引的位置来添加元素)
voidadd(index,element);
voidadd(index,Collection)
//List特有的取出方式之一
for(inti=0;i<ll.size();i++){
System.out.println(ll.get(i));
}
2、删除(删除相应索引位置的元素)
Object remove(index);//返回被删除的元素
3、修改(修改指定索引位置的元素,并返回修改前的元素)
ObjectSet(index,element)//返回被修改的元素
4、获取:
Object get (index);
int IndexOf(object);//返回此列表中第一次出现指定元素的索引,如果此列表不包含该素, //则返回-1.
int lastIndexOf(object);//返回此列表中最后一次出现指定的元素,如果此列表不包含该元素, //则返回-1.
List subList(int from,int to);//包含头,不包含尾,获取子列表。
代码如下: package com.wq.list; /** * 添加一个课程类,提供课程的选择 * @author LULEI * */ public class Courses { private String id;//课程序号 private String name;//课名 public Courses(){ } public Courses(String id,String name){ this.setId(id); this.setName(name); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试List的一些方法: package com.wq.list; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class ListTest { //用于存放备选课程的List public List courseToSelect; public ListTest(){ this.courseToSelect=new ArrayList(); } //用于courseToSelect添加备选课程 public void testAdd(){ //创建一个课程的实例,并通过使用add方法,将该实例 //添加到备选课程List中 Courses cr1=new Courses("1", "数据库"); courseToSelect.add(cr1);//将课程添加到备选课程List中 Courses temp=(Courses)courseToSelect.get(0);//选取List列表中的第一个元素 System.out.println("添加了课程:"+temp.getId()+"."+temp.getName()); Courses cr2=new Courses("2","JAVA"); courseToSelect.add(0, cr2); Courses temp2=(Courses)courseToSelect.get(0); System.out.println("添加了课程:"+temp2.getId()+"."+temp2.getName()); /* * 下面代码会出现越界的异常 Courses cr3= new Courses("4", "test"); courseToSelect.add(4,cr3); //Courses cr3=(Courses)courseToSelect.get(4); //System.out.println("添加了课程:"+cr3.getId()+"."+cr3.getName()); * */ Courses cr7=new Courses("1", "数据库"); courseToSelect.add(cr7);//将课程添加到备选课程List中 Courses temp7=(Courses)courseToSelect.get(2);//选取List列表中的第一个元素 System.out.println("添加了课程:"+temp7.getId()+"."+temp7.getName()); //addAll()方法的使用 Courses[] cr3={new Courses("3","高数"),new Courses("4","英语")}; courseToSelect.addAll(Arrays.asList(cr3));//将数组转换成List集合 Courses temp3=(Courses)courseToSelect.get(3); Courses temp4=(Courses)courseToSelect.get(4); System.out.println("添加了两门课:"+temp3.getId()+"."+temp3.getName() +temp4.getId()+"."+temp4.getName()); Courses[] cr4={new Courses("5","高等语文"),new Courses("6","数据处理")}; courseToSelect.addAll(2,Arrays.asList(cr4)); //将数组转换成List集合 Courses temp5=(Courses)courseToSelect.get(2); Courses temp6=(Courses)courseToSelect.get(3); System.out.println("添加了两门课:"+temp5.getId()+"."+temp5.getName() +temp6.getId()+"."+temp6.getName()); } /** * 创建一个Get方法,用于获取List中的元素的方法 */ public void testGet(){ int num=courseToSelect.size();//获取List的长度 System.out.println("可以选择的课程如下:"); for(int i=0;i<num;i++){ Courses cr=(Courses) courseToSelect.get(i); System.out.println(cr.getId()+"."+cr.getName()); } } /** * 使用迭代器的方法来获取List中的元素 * @param args */ public void testIterator(){ //迭代器是个借口,依赖集合存在 Iterator i=courseToSelect.iterator(); System.out.println("可以选择的课程如下(通过迭代器实现的):"); while(i.hasNext()){ Courses cr=(Courses)i.next(); System.out.println(cr.getId()+"."+cr.getName()); } } /** * 使用for each的方法来获取List中的元素 * @param args */ public void testForEach(){ System.out.println("可以选择的课程如下(通过foreach实现的):"); for(Object obj:courseToSelect){ Courses cr=(Courses)obj; System.out.println(cr.getId()+"."+cr.getName()); } } /** * 通过set()方法来修改List元素 * @param args */ public void testModify(){ courseToSelect.set(4, new Courses("7", "毛概")); } /** * 学会使用remove()方法来删除List中的元素 * 这种方法的参数是obj,还有一种remove方法的参数是索引、 * 如:remove(4);即可获得同样的效果 * @param args */ public void testRemove(){ Courses cr=(Courses) courseToSelect.get(4); System.out.println("将要删除的课程是:"+cr.getId()+"."+cr.getName()); courseToSelect.remove(cr); System.out.println("课程已删除"); testForEach(); } /** * 使用removeAll()方法来删除多个List中的对象 * @param args */ public void testRemoveAll(){ Courses[] crs={(Courses) courseToSelect.get(4), (Courses) courseToSelect.get(5)}; //removeAll的参数是一个集合,所以要将 //Courses数组转换成集合List courseToSelect.removeAll(Arrays.asList(crs)); testForEach(); } /** * 创建一个奇怪的方法,用来给List添加字符串 * @param args */ public void testAddString(){ System.out.println("到底能不能添加字符串呢!!"); courseToSelect.add("这是一个很无辜的字符串"); } public static void main(String[] args){ ListTest lt=new ListTest(); lt.testAdd(); lt.testGet(); lt.testIterator(); lt.testAddString(); lt.testForEach(); // lt.testModify(); // lt.testForEach(); // lt.testRemove(); // lt.testRemoveAll(); } }
接下来我们看看一个使用迭代器出错的代码:
主要代码如下:
ll.add(“qwe1”);
ll.add(“qwe2”);
ll.add(“qwe3”);
Iterator it=ll.iterator();//获取List集合的迭代器的对象
while(it.hasnext()){
Object obj=it.next();
if(obj.equals(“qwe2”)){
ll.add(“abc9”);//集合添加元素
}
else{
System.out.println(“next:”+obj);//打印元素
}
}
以上就是一段代码,但是在运行while循环中会出现异常:Java.util.concurrentModificationException。主要的原因是:在迭代器过程中,不要使用集合来操作元素,容易抛出异常。怎么解决呢???我们可以使用Iterator的子接口ListIterator来完成在迭代器中对元素进行更多的操作。
更换代码如下:
ll.add(“qwe1”);
ll.add(“qwe2”);
ll.add(“qwe3”);
ListIterator it=ll.listiterator();//获取List集合的迭代器的对象
while(it.hasnext()){
Object obj=it.next();
if(obj.equals(“qwe2”)){
it.add(“abc9”);//迭代器对象进行添加元素
}
else{
System.out.println(“next:”+obj);//打印元素
}
}
二、List的子类
-------Vector:内部是数组数据结构,是同步的(即线程安全的)。增删修改查询都很慢。(不常用)
-------ArrayList:内部是数组数据结构的,是不同步的。替代了Vector,查询的速度快。
------LinkedList:内部是链表的数据结构,是不同步的。增删元素的速度非常快。
这里我们做一个练习:使用LinkedList来模拟一个堆栈和队列的数据结构。
堆栈:先进后出(First In Last Out)FILO
队列:先进先出(First In First Out)FIFO
我们应该描述这样一个容器,给使用者提供一个容器对象完成这两种结构的一种。
LinkedList(可以实现队列和堆栈的功能)
常用的方法如下:
addFirst();
addLast();//从jdk1.6后改成 offerFirst(),和offerLast();
getFirst();//获取但不移除,如果链表为空。抛出NoSuchElementException
getLast();
从jdk1.6后上面两个改成:
peekFirst();//获取但不移除,如果链表为空,则返回null
peekLast();
removeFirst();//获取,且移除当前的元素。如果链表为空。抛出NoSuchElementException
removeLast();
从jdk1.6后上面两个改成:
poolFirst();//获取且移除当前的元素,如果链表为空,则返回null
poolLast();
代码的实现如下:
///队列类 package com.wq.linkedlist; import java.util.LinkedList; import java.util.List; public class DuiLie { //这个类是实现队列的功能的 LinkedList ls=new LinkedList();//内部是链表结构的list public DuiLie(){ } public void addElement(Object obj){ //ls.addLast(obj);//在后面添加元素 ls.offerLast(obj);//jdk1.6版本后的在后面添加元素方法 System.out.println(obj+"已经加入队列"); } public void removeElement(){ Object obj=ls.pollFirst();//jdk1.6版本的删除最前面的元素,取代了removeFirst()方法 System.out.println(obj+"已经出队列"); } } ///堆栈类 package com.wq.linkedlist; import java.util.LinkedList; public class DuiZhan { //这个类是实现堆栈的功能的 LinkedList ls=new LinkedList();//内部是链表结构的list public DuiZhan(){ } public void addElement(Object obj){ //ls.addLast(obj);//在后面添加元素 ls.offerLast(obj);//jdk1.6版本后的在后面添加元素方法 System.out.println(obj+"已经加入堆栈"); } public void removeElement(){ Object obj=ls.pollLast();//jdk1.6版本的删除最前面的元素,取代了removeLast()方法 System.out.println(obj+"已经退出堆栈"); } } /////测试上述两个类 package com.wq.linkedlist; public class test { public static void main(String[] args) { // TODO Auto-generated method stub DuiZhan dz=new DuiZhan();//实例化堆栈的对象 DuiLie dl=new DuiLie();//实例化队列的对象 //实现堆栈的功能 System.out.println("实现堆栈的功能"); dz.addElement(111); dz.addElement(222); dz.addElement(333); dz.addElement(444); dz.removeElement(); dz.removeElement(); dz.removeElement(); dz.removeElement(); System.out.println(); //实现队列的功能 System.out.println("实现队列的功能"); dl.addElement(111); dl.addElement(222); dl.addElement(333); dl.addElement(444); dl.removeElement(); dl.removeElement(); dl.removeElement(); dl.removeElement(); } }
运行结果如下:
实现堆栈的功能
111已经加入堆栈
222已经加入堆栈
333已经加入堆栈
444已经加入堆栈
444已经退出堆栈
333已经退出堆栈
222已经退出堆栈
111已经退出堆栈
实现队列的功能
111已经加入队列
222已经加入队列
333已经加入队列
444已经加入队列
111已经出队列
222已经出队列
333已经出队列
444已经出队列
三、ArrayList集合存数自定义对象
1、集合里存储的都是对象的引用,迭代器里迭代的也是集合中的引用
代码如下:
package com.wq.arraylist; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.wq.person.Person; /** * 该类主要完成 去除ArrayList中的重复元素 * @author LULEI * */ public class testArrayList { public static void main(String[] args) { // TODO Auto-generated method stub List li=new ArrayList(); testDemo1(li); } public static void testDemo1(List li) { //测试传统的对象 /* li.add("111"); li.add("111"); li.add("222"); li.add("333"); li.add("444"); li.add("333"); */ /* * 测试添加自定义的对象Person */ li.add(new Person("wq1",21)); li.add(new Person("wq2",22)); li.add(new Person("wq1",21)); li.add(new Person("wq3",23)); li.add(new Person("wq2",22)); li.add(new Person("wq3",23)); System.out.println(li); //调用换取单个元素的方法 li=getSingelElement(li); System.out.println(li); } public static List getSingelElement(List li) { // TODO Auto-generated method stub List temp=new ArrayList(); for(Iterator it=li.iterator();it.hasNext();){ Object obj=it.next(); if(!temp.contains(obj)){//如果不包含该元素 temp.add(obj); } } return temp; } }
四、Set集合
Set是个接口,元素不可以重复,是无序的。Set接口中的方法和Collection的一致。
Set的子类:
1、-----HashSet:此类实现的Set接口,由哈希表(实际上是一个HashMap)实例支持,它不保证Set的迭代顺序,但是允许使用null元素。
HashSet:内部结构是哈希表,是不同步的。
哈希表确定元素是否相同:
一、 判断的是两个元素的哈希值是否相同。如果相同,再判断两个对象的内容是否相同。
二、 判断哈希值是否相同,其实判断的是对象的hashCode()的方法。判断内容是否相同,用的是equals()方法。
三、 如果哈希值不同,那就不需要进行equals判断。
HashSet集合数据结构是哈希表,所以存储元素的时候,使用元素的hashCode()方法来确定位置,如果位置相同,再通过元素的equals方法来确定是否相同。
练习题:定义功能去除ArrayList的重复元素
注意:像ArrayList集合,在判断元素是否相同的时候,仅仅需要判断equals()方法。因为数据结构不同,对元素的判断依据也就一样。
代码如下:
package com.wq.person; public class Person extends Object { private String name; private int age; public Person() { super(); // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Person)) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { // TODO Auto-generated method stub return name+"...."+age; } } //hashset测试程序 package com.wq.hashset; import java.util.HashSet; import java.util.Iterator; import com.wq.person.Person; public class testHashSet { public static void main(String[] args) { // TODO Auto-generated method stub HashSet hs=new HashSet();//实例化一个hashset对象 hs.add(new Person("lisi1",21)); hs.add(new Person("lisi2",22)); hs.add(new Person("lisi3",23)); hs.add(new Person("lisi4",24)); hs.add(new Person("lisi4",24));//如果想在迭代中不出现相同的元素,需要 //通过覆写Person类的hashcode和equals方法 //使用迭代器进行迭代 for(Iterator it=hs.iterator();it.hasNext();){ Person pe=(Person)it.next(); System.out.println(pe.getName()+"---"+pe.getAge()); } } }
运行结果如下(由于无序这只是一种可能):
lisi4---24
lisi3---23
lisi2---22
lisi1---21
特别注意:如果希望元素不重复,但是要有序,这时可以考虑使用LinkedHashSet,它是HashSet的子接口。
2、----TreeSet:可以对Set集合的元素进行排序,不是同步的。
判断元素唯一性的方式就是根据比较方法compareTo()的返回结果,判断返回的结果是否为0,是0就表示相同的元素且不存储。否则就相反
TreeSet对元素进行排序的方式一:让元素具备比较功能,元素需要实现comparable接口,覆盖CompareTo()方法。
如果不要按照对象具备的自然顺序进行排序,如果对象不具备自然顺序。(即对象没有比较性,或者具备的比较性不是我们所需要的)这个时候怎么办???
TreeSet对元素进行排序的方式二:(生成一个比较器)让集合自身具备比较的功能,定义一个类,实现Comparator接口,覆盖compare方法,将该类的对象作为参数传递给TreeSet集合的构造函数。
代码演示如下:
//Person类 package com.wq.person; //需要实现Comparable接口 public class Person extends Object implements Comparable{ private String name; private int age; public Person() { super(); // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Person)) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { // TODO Auto-generated method stub return name+"...."+age; } //需要覆写的compareTo方法 //这里我的思路是先比较age的大小,如果age相等,则 //接着比较name的字典顺序大小 @Override public int compareTo(Object o) { // TODO Auto-generated method stub Person per=(Person) o;//实现强制类型转换 if(this.age>per.age){ return 1; }else if(this.age<per.age){ return -1; }else{//如果年纪相等就比较名字的字典顺序大小 int temp=this.name.compareTo(per.name); return temp; } } } //自己写的Comparator接口 package com.wq.comparator; import java.util.Comparator; import com.wq.person.Person; public class ComparatorByName implements Comparator { /** * 覆写compare方法,生成一个比较器。这里我们用name来作为比较 */ @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub Person p1=(Person)o1; Person p2=(Person)o2; int temp=p1.getName().compareTo(p2.getName());//获取两个对象的name比较的结果 return temp==0?p1.getAge()-p2.getAge():temp; } } //测试类。用于测试CompareTo()方法和Comparable接口 package com.wq.TreeSet; import java.util.Iterator; import java.util.TreeSet; import com.wq.comparator.ComparatorByName; import com.wq.person.Person; public class testTreeSet { public static void main(String[] args) { // TODO Auto-generated method stub //测试实现Comparable接口的比较功能 System.out.println("测试实现Comparable接口的比较功能"); testComparableDemo(); System.out.println("测试实现Comparator接口,作为一个比较器来进行比较的功能"); //测试实现Comparator接口,作为一个比较器来进行比较的功能 testComparatorDemo(); } public static void testComparatorDemo() { TreeSet ts=new TreeSet(new ComparatorByName());//实例化对象,并且确定比较器 //添加自定义对象 //在添加元素时,自定义的对象必须实现Comparator接口,同时要覆盖compare方法 //否则就会报错 ts.add(new Person("zhangsan",22)); ts.add(new Person("zhaoliu",24)); ts.add(new Person("zhouqi",25)); ts.add(new Person("wuba",28)); ts.add(new Person("lisi",26)); ts.add(new Person("wangwu",25)); for(Iterator it=ts.iterator();it.hasNext();){ Person per=(Person)it.next(); System.out.println(per); } } public static void testComparableDemo() { TreeSet ts=new TreeSet();//实例化对象, //添加自定义对象 //在添加元素时,自定义的对象必须实现Comparable接口,同时要覆盖compareTo方法 //否则就会报错 ts.add(new Person("zhangsan",22)); ts.add(new Person("zhaoliu",24)); ts.add(new Person("zhouqi",25)); ts.add(new Person("wuba",28)); ts.add(new Person("lisi",26)); ts.add(new Person("wangwu",25)); for(Iterator it=ts.iterator();it.hasNext();){ Person per=(Person)it.next(); System.out.println(per); } } }
运行结果如下:
测试实现Comparable接口的比较功能(以年龄大小)
zhangsan....22
zhaoliu....24
wangwu....25
zhouqi....25
lisi....26
wuba....28
测试实现Comparator接口,作为一个比较器来进行比较的功能(以名字的字典顺序)
lisi....26
wangwu....25
wuba....28
zhangsan....22
zhaoliu....24
zhouqi....25
练习:TreeSet集合练习,字符串长度的排序
分析:Java代码中。TreeSet默认的会为字符串进行字典顺序大小的排序,但这不符合我们的要求。这个时候怎么办,我们必须要用到比较器。即comparator接口来实现。
具体代码实现如下:
//自定义的比较器 package com.wq.comparator; import java.util.Comparator; import com.wq.person.Person; /* * 生成一个比较器,用来比较字符串的长度大小,如果长度相等则比较字符的字典顺序大小 */ public class ComparatorByLength implements Comparator { @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub String str1=(String)o1; String str2=(String)o2; int temp=str1.length()-str2.length(); return temp==0?str1.compareTo(str2):temp; } } //测试类 package com.wq.TreeSet; import java.util.Iterator; import java.util.TreeSet; import com.wq.comparator.ComparatorByLength; import com.wq.person.Person; /** * 这个练习是对TreeSet集合的练习 * 主要是进行字符串的长度的排序 * @author LULEI * */ public class testTreeSetDemo { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet ts=new TreeSet(new ComparatorByLength());//在构造函数中添加相应的构造器 ts.add("asdfdf"); ts.add("dds"); ts.add("fghf"); ts.add("as"); ts.add("t"); ts.add("fdsfsg"); for(Iterator it=ts.iterator();it.hasNext();){ Object o=(Object)it.next(); System.out.println(o); } } }
运行结果如下:
t
as
dds
fghf
asdfdf
fdsfsg
总结:List: 1---ArrayList 2---LinkedList
Set 1---HashSet --LinkedHashSet
2---TreeSet
注意,后缀名就是该集合所属的体系,前缀名就是该集合的数据结构。
看到array:就要想到数组,就要想到查询快,有角标。如果不希望出现重复的元素则需要覆盖equals()方法。
看到link就要想到链表,就要想到增删快,就要想到add,get,remove+first(last)的方法。
看到hash就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashCode()和equals()方法。
看到tree就要想到二叉树,就要想到排序,就要想到两个接口:comparator和comparable。
并且通常这些常用的容器都是不同步的。
五、Map集合
Map<K,V>;一次添加一对元素。而Collection一次添加一个元素。Map集合也称为双列集合,Collection集合也称为单列集合。其实Map集合中存储的就是键值对,且保证键(K)的唯一性。
常用的方法:
1、添加
value put(key,value);//返回前一个与key关联的值,如果没有则返回null
2、删除
value remove(key);//根据指定的key删除这个键值对
void clear();//清除这个Map集合
3、判断
boolean containsKey(key);
boolean containsValue(value);
boolean isEmpty();//判断是否为空
4、获取
value get(key);//用过键来返回值,如果没值该键返回null。当然可以通过返回null来判断是否包含指 //定的键(K)
int size();//获取键值对的个数
Map接口是如何实例化的??
如:Map<Integer,String> map=newHashMap<Integer,String>();//实例化一个 //HashMap对象
5、注意:问题:如何获取map中的所有的元素???
取出map中的元素,原理如下:通过keySet方法获取map中所有键所在的Set集合中,再通过Set的迭代器获取到每个键。然后对每个键通过map集合的get()方法获取其所对应的值。
代码演示如下:
package com.wq.map; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * 测试Map的一些基本的方法 * * @author LULEI * */ public class mapDemo1 { public static void main(String[] args) { // TODO Auto-generated method stub Map<Integer, String> hm=new HashMap<Integer,String>();//实例化对象 testMapDemo1(hm);//这个方法实现了一些基本方法 System.out.println(); System.out.println(); testMapDemo2(hm); //这个方法实现Map集合中如何取出所有的元素 //1、要使用到keySet()方法来获取key值得Set集合 //2、依次的迭代Set集合中的key值,最后通过get(key)来获取键值对 } public static void testMapDemo2(Map<Integer, String> hm) { // TODO Auto-generated method stub String str2=hm.put(2, "lisi"); //System.out.println("此时给相同的key赋键值,返回的上一个键值是:"+str2);//此时lisi //会覆盖wangcai的,同时put方法会返回之前的键值对 hm.put(8, "wq"); hm.put(7, "ll"); hm.put(6, "pp"); Set<Integer> s=hm.keySet();//获取key的Set集合 //使用迭代器来迭代集合 for(Iterator<Integer> it=s.iterator(); it.hasNext();){ Integer i=it.next(); System.out.println("使用迭代获取的元素:"+hm.get(i) ); } } public static void testMapDemo1(Map<Integer, String> hm) { //添加 String str1=hm.put(2, "wangcai"); System.out.println("此时给相同的key赋键值,返回的上一个键值是:"+str1);//此时由于key //刚刚被赋值,所以之前是没有键值对的 String str2=hm.put(2, "lisi"); System.out.println("此时给相同的key赋键值,返回的上一个键值是:"+str2);//此时lisi //会覆盖wangcai的,同时put方法会返回之前的键值对 hm.put(7, "ll"); hm.put(8, "wq"); hm.put(6, "pp"); System.out.println("所有的键值对如下:"+hm); //获取 System.out.println("获取相应的key值得键值:"+hm.get(7)); System.out.println("获取相应的key值得键值:"+hm.get(4)); //删除 hm.remove(6);//删除key为6的键值 System.out.println("删除key为6的键值后的map"+hm); } }
运行结果如下:
此时给相同的key赋键值,返回的上一个键值是:null
此时给相同的key赋键值,返回的上一个键值是:wangcai
所有的键值对如下:{2=lisi,6=pp, 7=ll, 8=wq}
获取相应的key值得键值:ll
获取相应的key值得键值:null
删除key为6的键值后的map{2=lisi, 7=ll, 8=wq}
使用迭代获取的元素:lisi
使用迭代获取的元素:pp
使用迭代获取的元素:ll
使用迭代获取的元素:wq
上面提到的只是一种方法,另一种方法是entrySet()。该方法将键与值得映射关系作为对象存储到了Set集合中,而这个映射关系的类型就是Map.EntryKey类型。(打个比方:键是丈夫,值就是妻子,映射关系就是结婚证)。
Entry本身就是一个嵌套的静态接口。
图解如下:
6、values方法(如果只想获取值不要键怎么办???)
Collection<V> values()方法:返回映射关系中包含的值得Collection集合。注意只含值,然后利用Iterator迭代器来迭代即可获取所有的值。
7、Map常用的子类
--Hashtable:内部结构是哈希表,是同步的。不支持null作为键和值。
---Properties:Hashtable的子类,用来存储键值对配置文件的信息, 可以和IO口技术向结合。
--HashMap:内部结构是哈希表,不是同步的,支持null作为键和值。
--TreeMap:内部结构是二叉树,不是同步的,支持null作为键和值。
代码演示如下:
//Person类 package com.wq.person; public class Person extends Object implements Comparable{ private String name; private int age; public Person() { super(); // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Person)) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { // TODO Auto-generated method stub return name+"...."+age; } //需要覆写的compareTo方法 //这里我的思路是先比较age的大小,如果age相等,则 //接着比较name的字典顺序大小 @Override public int compareTo(Object o) { // TODO Auto-generated method stub Person per=(Person) o;//实现强制类型转换 if(this.age>per.age){ return 1; }else if(this.age<per.age){ return -1; }else{//如果年纪相等就比较名字的字典顺序大小 int temp=this.name.compareTo(per.name); return temp; } } } //student类继承Person类 package com.wq.person; public class Student extends Person{ private String name; private int age; public Student(String name, int age) { super(name,age); } public Student(){ super(); } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } //测试HashMap类 package com.wq.map; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import com.wq.person.Student; public class Hashmaptest { public static void main(String[] args) { // TODO Auto-generated method stub HashMap<Student,String> hm=new HashMap<Student,String>(); //添加学生对象,和学生的归属地 hm.put(new Student("lisi",24 ),"南京"); hm.put(new Student("zhangsan",44 ),"北京"); hm.put(new Student("wangwu",32 ),"天津"); hm.put(new Student("xiaoqiang",18 ),"上海"); hm.put(new Student("xiaoqiang",18 ),"后海"); Set<Student> s=hm.keySet(); Iterator<Student> it=s.iterator(); while(it.hasNext()){ Student st=it.next(); String value=hm.get(st); System.out.println(st.getName()+".."+st.getAge()+"...."+value); } } }
运行代码如下:
xiaoqiang..18....后海
wangwu..32....天津
zhangsan..44....北京
lisi..24....南京
//测试TreeMap类 //自定义比较器 package com.wq.comparator; import java.util.Comparator; import com.wq.person.Person; public class ComparatorByName implements Comparator { /** * 覆写compare方法,生成一个比较器。这里我们用name的字典顺序来作为比较 */ @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub Person p1=(Person)o1; Person p2=(Person)o2; int temp=p1.getName().compareTo(p2.getName());//获取两个对象的name比较的结果 return temp==0?p1.getAge()-p2.getAge():temp; } } //TreeMap测试部分 package com.wq.map; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import com.wq.comparator.ComparatorByName; import com.wq.person.Student; public class TreeMaptest { public static void main(String[] args) { // TODO Auto-generated method stub //添加一个比较器,用来排序 TreeMap<Student,String> hm=new TreeMap<Student,String>(new ComparatorByName()); //添加学生对象,和学生的归属地 hm.put(new Student("lisi",24 ),"南京"); hm.put(new Student("zhangsan",44 ),"北京"); hm.put(new Student("wangwu",32 ),"天津"); hm.put(new Student("xiaoqiang",18 ),"上海"); hm.put(new Student("xiaoqiang",28 ),"后海"); //使用entrySet来获取全部元素 Iterator<Map.Entry<Student, String>> it=hm.entrySet().iterator(); while(it.hasNext()){ Map.Entry<Student, String> mp=it.next(); Student st=mp.getKey(); String value=mp.getValue(); System.out.println(st.getName()+".."+st.getAge()+"...."+value); } } }
运行结果:
lisi..24....南京
wangwu..32....天津
xiaoqiang..18....上海
xiaoqiang..28....后海
zhangsan..44....北京
相信以上的代码能够帮助我们更好地理解Map的子类。以及获取所有子类元素的方法:keySet()和EntrySet()两种方法。接下来看看练习:
练习题:” aFGDHRTYdshgfd./,/g1uAAD898 styefbhbhad”,这样一个随机的字符串。获取该字符串中每个字符出现的次数。并最终以a(n),b(m)……这样的格式打印出来。
分析如下:对于结构的显示,字符和出现次数之间存在着映射的关系。而且这种关系很多。既然很多我们就需要存储,但是能存储映射关系的有数组和Map集合。这时我们需要考虑:关系一方有序号编码吗?答案是没有,于是我们就选用Map集合,同时又发现可以保证唯一性的一方具备着顺序如:a,b,c,d,……。所以最后的选择是TreeMap集合。
操作思路:这个集合最后存储的是字符与次数的对应关系。
1、因为操作的是字符串中的字符,所以先将字符串变成字符数组。
2、遍历字符数组,用每一个字符作为键去查询Map集合这个表。
3、如果该键不存在,就将该字母作为键,1作为值,存储到Map集合中。
4、如果该键存在,就将该字符键对应的值加1,在将该字母与加1后的值存在Map集合中。键相同,只会覆盖,这样就记录了字符的次数。
5、遍历字符数组结束后,Map集合就记录了所有的字符出现的次数。一次迭代输出即可是实现。
代码实现如下:
package com.wq.map; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; /** * 练习:" aFGDHRTYdshgfd./,/g1uAAD898 styefbhbhad "获取该字符串中, * 每一个字母出现的次数,要求打印的结果如下 * a(1)b(2)c(..)... * @author LULEI * */ public class MapPrictice { public static void main(String[] args) { // TODO Auto-generated method stub //声明要变换的字符串 String str="aFGDHRTYdshgfd./,/g1uAAD898 styefbhbhad"; str=StringTocharNum(str); System.out.println(str); } public static String StringTocharNum(String str) { // TODO Auto-generated method stub //1、第一步是将字符串转换成字符数组 char[] ch=str.toCharArray(); //2、定义一个map集合,用于存储字母(键)和出现的次数(值) Map<Character,Integer> mp=new TreeMap<Character,Integer>(); //3、开始进行循环的判断 //当出现非字母的字符时,增加如下的判断 for (int i = 0; i < ch.length; i++) { if(!(ch[i]>='a' && ch[i]<='z'|| ch[i]>='A' && ch[i]<='Z')){ continue;//如果不是字符则结束本次循环 } Integer value=mp.get(ch[i]);//注意这里返回的是int的包装类。之前Map是这样定义的Map<Character,Integer> if(value==null){ mp.put(ch[i], 1); }else{ mp.put(ch[i], value+1); } } //4、将字母以次数打印出来 return printCharNum(mp);//调用打印函数 } private static String printCharNum(Map<Character, Integer> mp) { //定义一个可以改变字符长度的字符串 StringBuilder sb=new StringBuilder(); //取出Map中的所有元素 Iterator<Character> it=mp.keySet().iterator(); while(it.hasNext()){ Character ch=it.next(); Integer in=mp.get(ch); sb.append(ch+"("+in+")");//直接在后面添加字符串 } return sb.toString();//最后转换为string类型输出 } }
运行结果如下:
A(2)D(2)F(1)G(1)H(1)R(1)T(1)Y(1)a(2)b(2)d(3)e(1)f(2)g(2)h(3)s(2)t(1)u(1)y(1)
补充:接下来补充一个Collection.Sort()方法的实例:可以看看代码:
//collection.sort()方法的测试类,这个类还需要Students类和一个自定义比较器//Studentscomparator类 package com.wq.list; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import javax.swing.text.html.ListView; /** * 将要完成 * 1.通过Collections.sort(),对Integer泛型的List集合进行排序 * @author LULEI * */ public class CollectionsTest { /** * 通过Collections.sort(),对Integer泛型的List集合进行排序 * 使用Random类来生成不相等的随机数10个 */ public void testListSort1(){ List<Integer> integer=new ArrayList<Integer>(); Random random=new Random(); //产生一个随机种子对象 int k=0; //生成10个随机数 for(int i=0;i<10;i++){ do{ k=random.nextInt(100);//生成100以内的一个随机数 }while(integer.contains(k));//判断随机数是否重复,如果不重复就跳出while循环 integer.add(k); //向list集合中添加元素 System.out.println(k+"已经成功添加"); } System.out.println("-----排序前------"); for(Integer it:integer){ System.out.println("元素:"+it); } //调用sort()方法来进行排序 Collections.sort(integer); //直接调用父方法的sort()进行排序 System.out.println("--------排序后--------"); for(Integer it:integer){ System.out.println("元素:"+it); } } /** * 通过Collections.sort(),对String泛型的List集合进行排序 * 向List集合中添加3个字符串 */ public void testListSort2() { List<String> str=new ArrayList<String>(); str.add("microsoft"); str.add("baidu"); str.add("google"); System.out.println("----排序前----"); for(String ss:str){ System.out.println(ss); } Collections.sort(str); System.out.println("----排序后----"); for(String ss:str){ System.out.println(ss); } } /** * 通过Collections.sort(),对String泛型的List集合进行排序 * 向List里添加十条随机字符串 * 字符串的长度要不大于10 * 每个字符串的每个字符都是随机生成的,但可以重复 * 每个字符串是不可以重复的 * @param args */ public void testListOfString(){ List<String> newStr=new ArrayList<String>();//用于存储字符串的 Random randomLength=new Random();//随机生成字符串的长度 //所有字符查询表 String table="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; //生成10个字符串 for(int i=0;i<10;i++){ StringBuilder sb=new StringBuilder();//用来存储随机产生的字符串 do{ //确定当前字符串的长度 int length=randomLength.nextInt(11);//注意每个字符串不能大于10个字符 while(length==0){//避免length的值为0,否则这样就会产生空字符串 length=randomLength.nextInt(11); } for(int m=0;m<length;m++){ int pos=randomLength.nextInt(table.length());//获取字符查询表中任意一个随机的位置 sb.append(table.charAt(pos));//将该位置上的字符添加到sb中 } }while(newStr.contains(sb.toString()));//判断是否有重复的字符串,如果集合中不含有该字符串则退出while循环 newStr.add(sb.toString());//使用toString方法转化为String类型 } System.out.println("====排序前====="); for(String stBd:newStr){ System.out.println(stBd); } //调用sort()方法进行排序 Collections.sort(newStr); System.out.println("====排序后====="); for(String stBd2:newStr){ System.out.println(stBd2); } Collections.sort(newStr); } /** * 如何给Students类型的List集合元素进行排序 * 直接使用Collections.sort()方法是不行的,必须先让Students类继承comparable接口 * 并且覆写comparable接口的compareTo()方法。然后确定新的比较规则:此处我们设置如下 * this.id.compareTo(o.id);通过比较id号的字符大小顺序来进行排序 * @param args */ public void testStudentsList(){ List<Students> liStu=new ArrayList<Students>();//实例化一个集合,用来存储Students对象 Random random=new Random();//生成随机种子用于随机生成几个不相等的id号 //添加3个Students的对象 liStu.add(new Students(Integer.toString(random.nextInt(1000)), "tim")); liStu.add(new Students(Integer.toString(random.nextInt(1000)), "jack")); liStu.add(new Students(Integer.toString(random.nextInt(1000)), "lucy")); liStu.add(new Students(Integer.toString(100000), "lily")); /* * 直接使用Collections.sort()方法是不行的,必须先让Students类继承comparable接口 * 并且覆写comparable接口的compareTo()方法。然后确定新的比较规则:此处我们设置如下 * this.id.compareTo(o.id);通过比较id号的字符大小顺序来进行排序 */ System.out.println("=====排序前===="); for(Students stu:liStu){ System.out.println(stu.getId()+"."+stu.getName()); } Collections.sort(liStu); System.out.println("=====排序后===="); for(Students stu:liStu){ System.out.println(stu.getId()+"."+stu.getName()); } /** * 接下来是用comparator接口来确定新的临时比较规则:使用姓名来排序 * 过程如下:1、定义一个StudentComparator类,然后 * 让这个类继承comparator接口,然后覆写该接口的compare()方法 * 2、然后调用Collections.sort()方法来进行排序 */ Collections.sort(liStu,new StudentsComparator()); System.out.println("-------按照名字进行排序---------"); System.out.println("=====排序后===="); for(Students stu:liStu){ System.out.println(stu.getId()+"."+stu.getName()); } } public static void main(String[] args) { // TODO Auto-generated method stub CollectionsTest ct=new CollectionsTest(); //排序Integer类型的List ct.testListSort1(); //排序String类型的List // ct.testListSort2(); //排序随机生成的String类型的List ct.testListOfString(); //排序Students类 ct.testStudentsList(); } } //Students类 package com.wq.list; import java.util.HashSet; import java.util.Set; /** * 学生类 * @author LULEI * */ public class Students implements Comparable<Students>{ private String name; private String id; public Set<Courses> courses;//用于后面添加课程 public Students(String id,String name){ this.setId(id); this.setName(name); //Set是一个接口,不能直接实例化,通过HashSet()对courses进行实例化 this.courses=new HashSet<Courses>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Students)) return false; Students other = (Students) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Students o) { // TODO Auto-generated method stub //将比较规则设置为id号 return this.id.compareTo(o.id); } } //StudentsComparator类 package com.wq.list; import java.util.Comparator; public class StudentsComparator implements Comparator<Students> { @Override public int compare(Students o1, Students o2) { // TODO Auto-generated method stub //将规则改成比较名字 return o1.getName().compareTo(o2.getName()); } }
运行结果如下:
57已经成功添加
22已经成功添加
65已经成功添加
52已经成功添加
27已经成功添加
90已经成功添加
38已经成功添加
77已经成功添加
47已经成功添加
21已经成功添加
-----排序前------
元素:57
元素:22
元素:65
元素:52
元素:27
元素:90
元素:38
元素:77
元素:47
元素:21
--------排序后--------
元素:21
元素:22
元素:27
元素:38
元素:47
元素:52
元素:57
元素:65
元素:77
元素:90
====排序前=====
Zj
gkjvUfLB
WgPiL3VX
Xj2DtAtL9
kyrkT9ILYa
G
s0FfBD
bZR
eDA
pVihS
====排序后=====
G
WgPiL3VX
Xj2DtAtL9
Zj
bZR
eDA
gkjvUfLB
kyrkT9ILYa
pVihS
s0FfBD
=====排序前====
319.tim
606.jack
464.lucy
100000.lily
=====排序后====
100000.lily
319.tim
464.lucy
606.jack
-------按照名字进行排序---------
=====排序后====
606.jack
100000.lily
464.lucy
319.tim
XXiaoLEI整理于2015-04-06 。
相关文章推荐
- JAVA常用集合框架用法详解基础篇一之Colletion接口
- JAVA常用集合框架用法详解——提高篇
- JAVA常用集合框架用法详解基础篇二之Colletion子接口List
- JAVA常用集合框架用法详解基础篇三之Colletion子接口Set
- Java集合排序及java集合类详解:集合框架中常用类比较
- Map、Set、Iterator迭代详解与 Java平台的集合框架
- Java语言基础-常用对象API(二)集合框架
- java 集合框架详解
- java中集合常用类及其详解
- Map、Set、Iterator迭代详解与Java平台的集合框架
- Java常用集合详解
- Java的常用集合框架
- Map、Set、Iterator迭代详解与Java平台的集合框架
- Map、Set、Iterator迭代详解与Java平台的集合框架
- Map、Set、Iterator迭代详解与Java平台的集合框架
- java常用集合框架图
- java中常用的集合框架
- JAVA中集合框架一些常用类的总结
- Java学习系列(七)Java面向对象之集合框架详解(上)
- Java学习系列(七)Java面向对象之集合框架详解(上)