集合框架
概述
面向对象语言对事物的描述都是以对象的形式体现的,为了方便对多个对象的操作,就对对象进行存储,集合就是存处对象最常用的一种方式,数据多了用对象存,对象多了就用集合存。
集合和数组都是容器,但是它们之间是有区别的。
数组的长度是固定的,集合的长度时刻变得,集合中只能存对象,而数组中还可以存基本数据类型,但数组不能存不同数据类型的对象,集合可以。
集合作为一个容器,它分了很多种,java对这些容器进行了划分和描述,这些容器有共性也有特性,我们把不同集合间的关系用一张图来表示:
出现这么多容器的原因就是:每一个容器对数据的存储方式都会有不同,这种存储方式我们称之为数据结构。
集合的共性方法
需要注意的是集合中存的并不是对象实体,而是对象的引用或地址。
根据参阅顶层创建底层的思想,我们先来看Collection接口中的共性方法。
1,添加
add(Object obj):add方法的参数类型是Object。以便于接收任意类型对象;
addAll(Collection c):添加另一个集合中的所有元素。
2,删除
remove(Object obj):删除某一个元素;
removeAll(Collection c);取两个集合的交集,并从调用者中删除这个交集包含
的所有元素;
clear():清空集合。
3,判断。
contains(Object obj):判断是否包含某元素;
containsAll(Collection c):判断一个集合是否是另一个集合的子集;
isEmpty():判断集合是否为空。
4,获取
iterator():迭代器;
size():获取集合的大小。
5,获取交集。
retainAll():取交集。
迭代器
取出集合中的元素,实际开发时,我们要做的是取出元素进行操作,并不是简简单单的打印。
什么是迭代器?
其实就是集合取出元素的方式。
集合中存放了元素,想要操作元素,定义内部类进行操作最为方便,这个内部类就完成了取出动作的定义,每个容器中都有这个内部类,以后再产生容器又要定义这个内部类,发现再取出的时候,一般都会做判断和取出动作,所以就把取出方式定义在集合内部,这样取出方式能直接访问集合内的元素,那么取出方式就被定义成了内部类,而每一个容器的数据结构不同,所以取出的动作也不同,但是有共性内容,判断和取出,那么我们可以将共性抽取,这个功能是扩展功能,把这些共性抽取出来形成接口,那么这些内部类都符合一个规则,该规则是Iterator,如何获取集合的取出对象呢?通过一个方法:inerator()。
其实就相当于我们现实生活中的夹子取娃娃的机器,大家去商场,都会看到这样的机器,每个机器里的夹子都不同,但它们都会对娃娃进行取出等操作,怎么操作,夹子最清楚,而且夹子会去夹机器内部的娃娃,所以我们就把夹子放在了机器内部。
迭代器中的方法
hasNext():判断是否还有下一个元素,是就返回true,否则返回false;
next():获取下一个元素;
remove:删除元素;
我们通过一段代码来演示如何用迭代方法取出集合中的元素:
import java.util.*;
class IteratorDemo
{
public static void main(String[] args)
{
getElement();
}
public static void getElement()
{
ArrayList al = new ArrayList();
//1,添加元素。
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
Iterator it = al.iterator();//获取迭代器,用于取出集合中的元素。
while(it.hasNext())//判断是否有下一个元素
{
System.out.println(it.next());//获取元素并打印
}
}
}
运行的结果是:
List集合
Collection
|--List: 元素是有序的,可重复,因为该集合体系有索引;
|--ArrayList:底层数据结构是数组结构,它的特点是查询速度快,增删稍
慢,线程不同步;
|--LinkedList:底层使用的是链表结构,它的特点是增删速度快,查询比较
慢,线程不同步;
|--Vector:底层是由的数据结构是数组结构,和ArrayList一样,它是线程同
步的;
List集合的共性方法
凡是可以操作角标的方法,都是List集合所特有的方法。
增加元素:add(index,element);
add(index,collection);
删除元素:remove(index);删除成功,返回true,失败返回false,
修改元素:set(index,element);
查找元素:get(index );
subList(fromIndex,toIndex);
listIterator();
ListIterator列表迭代器
它是List集合特有的迭代器,是Iterator的子接口。
我们获取到的iterator迭代器,只能对元素进行判断取出和删除操作,如果我们想在迭代过程中,进行添加或者其他操作,那就要用到列表迭代器,否则就会产生并发访问的安全隐患。
import java.util.*;
class IteratorDemo
{
public static void main(String[] args)
{
getElement();
}
public static void getElement()
{
ArrayList al = new ArrayList();
//1,添加元素。
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
Iterator it = al.iterator();//获取迭代器,用于取出集合中的元素。
while(it.hasNext())//判断是否有下一个元素
{
Object obj = it.next();
if(obj.equals("java02"))
al.add("java007");
System.out.println("obj="+obj);//获取元素并打印
}
}
}
编译是没有问题的,我们看一下运行结果:
ConcurrentModificationException:这个是并发访问异常!在迭代时,不可以通过集合对象的方法操作几盒中的元素,会发生并发修改异常,所以在迭代时,只能用迭代器的方法操作元素,而iterator的方法时有限的,只能对元素进行判断,取出和删除操作,要使用添加等其他操作,就要使用的Iterator的子接口ListIterator,该接口只能通过List集合的listIterator方法获取。
列表迭代器除了增删操作外,还有set修改方法,进行逆向迭代:hasPrevious(),判断前面有没有元素,previous(),获取前一个元素。
Vector中的枚举:Enumaeration
枚举是Vector集合特有的取出元素的方式。
其实枚举和迭代是一样的,因为枚举的名称和方法的名称过长,所以被迭代取代了。
举个例子来对枚举取出元素的方式进行演示
import java.util.*;
class VectorDemo
{
public static void main(String[] args)
{
getElement();
}
public static void getElement()
{
Vector v = new Vector();
v.add("java01");
v.add("java02");
v.add("java03");
Enumeration en = v.elements();
while(en.hasMoreElements())//判断是否有下一个元素
{
System.out.println(en.nextElement());//获取元素并打印
}
}
}
运行结果:
LinkedList集合
特有方法:
1、增加元素
addFirst();
addLast();
2、获取元素:获取元素,但不删除元素。
getFirst();
getLast();
3、删除元素:获取并删除元素。
removeFirst();
removeLast();
在jdk1.6之后出现了替代的方法add--->offer;get--->peek;remove--->poll;在删除和获取元素时,如果列表为空,这些方法不会发生NoSuchElementException,会返回一个null。
练习:使用LinkedList模拟一个堆栈或者队列数据结构。
/*
需求:使用LinkedList模拟一个堆栈或者队列数据结构。
堆栈:先进后出 如同一个杯子。
队列:先进先出 First in First out FIFO 如同一个水管。
*/
import java.util.*;
class DuiLie
{
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
public void myAdd(Object obj)//模拟add方法
{
link.addFirst(obj);
}
public Object myGet_1()//模拟删除方法
{
return link.removeFirst();
}
public Object myGet_2()//模拟删除方法
{
return link.removeLast();
}
public boolean isNull()//模拟判断集合是否为空
{
return link.isEmpty();
}
}
class LinkedListTest
{
public static void main(String[] args)
{
DuiLie dl = new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull())
{
//System.out.println(dl.myGet_1());//先进后出,模拟堆栈
System.out.println(dl.myGet_2());//先进先出,模拟队列
}
}
}
ArrayList练习一:去除ArrayList集合中的重复元素。
import java.util.*;
/*
去除ArrayList集合中的重复元素。
思路:定义一个临时容器,对指定的集合进行遍历,遍历过程中判断这个元素是否在我们定义的临时容器中,
如果不在就将该元素添加到这个临时定义的容器中,最后将这个集合作为返回值,返回给调用者。
*/
class ArrayListTest
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java01");
al.add("java02");
al.add("java01");
al.add("java03");
System.out.println(al);
al = singleElement(al);
System.out.println(al);
}
public static ArrayList singleElement(ArrayList al)
{
//定义一个临时集合容器。
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!newAl.contains(obj))
newAl.add(obj);
}
return newAl;
}
}
ArrayList练习二:将自定义对象作为元素存到ArrayList集合中,并去除重复元素,比如:存人对象,同姓名同年龄,视为同一个人,为重复元素。
import java.util.*;
/*
需求:将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。
思路:
1,对人描述,将数据封装进人对象。
2,定义容器,将人存入。
3,取出。
*/
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public boolean equals(Object obj)//复写equals方法,因为从Object类继承来的equals方法只是比较地址值
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;//名字,姓名都不相同才是同一个对象
}
public String getName()//实际开发get,set都要有!
{
return name;
}
public int getAge()
{
return age;
}
}
class ArrayListTest2
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add(new Person("lisi01",30));
al.add(new Person("lisi02",32));
al.add(new Person("lisi02",32));
al.add(new Person("lisi04",35));
al.add(new Person("lisi03",33));
al.add(new Person("lisi04",35));
al = singleElement(al);
Iterator it = al.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
public static ArrayList singleElement(ArrayList al)
{
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!newAl.contains(obj))//contains remove依赖的都是equals方法
newAl.add(obj);
}
return newAl;
}
}
运行结果是:
List集合判断元素是否相同,依据是元素的equals方法,这个equals方法在底层是自动被调用的,remove,contains依赖的都是该方法,数据结构不同,依赖的比较方法是不同的,ArrayList和LinkedList依赖的都是equals方法。
Set集合
特点:
Set集合中的元素是无序的,也就是说存入和取出的顺序不一定一致,元素不可以重复。
Set集合的功能和Collection的功能是一致的。
常见的子类
HashSet:底层数据结构是哈希表,是线程不安全的,不同步。
TreeSet:底层是二叉树数据结构,是线程不安全的,不同步。
HashSet集合特点:
HashSet集合存数据是按照哈希表来存储的,存入时,先比较哈希值是否相同,如果不同,再比较是否是同一个对象,所以说HashSet是按照hashCode和equals来保证对象的唯一性的。
所以说,在我们创建一个对象是,要复写hashCode和equals方法,有可能这个对象要放到HashSet集合中。
HashSet集合判断和删除依赖的也是hashCode和equals方法,先判断hashCode,在判断equals。
TreeSet集合的特点:
可以对set集合中的元素进行排序。
TreeSet对存入集合对象的要求是必须具备比较性,让对象实现去实现Comparable接口,并复写接口中的compareTo方法,这种方式我们称之为元素的自然排序,下面我们用代码来进行演示(这里为了演示排序,我就不考虑重复元素了):
import java.util.*;
/*
需求:往TreeSet集合中存储自定义对象学生,想按照学生的年龄进行排序。
*/
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)//复写compareTo方法,自定义比较方式;
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
int num = new Integer(this.age).compareTo(new Integer(s.age));//Integer实现了Comparable,已具备比较性;
if(num==0)
return this.name.compareTo(s.name);//String也具备比较性,首要条件相同时,要比较次要条件;
return num;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi08",24));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
运行结果是:
TreeSet的第二种排序方式
对元素进行排序的原理:
1,让元素自身具备比较性;
2,让集合具备比较性。
当元素自身不具备比较性时,或者说元素所具备的比较性不是我们所需要的,这时就需要让集合自身具备比较性,java提供了这种便利,它让集合初始化的时候就有比较方式,这个方式就是Comparator比较器,我们可以自定义一个比较器,然后将这个比较器作为参数传递给集合的构造函数,这样,集合就具备比较性了。
如果元素和集合都具备比较性,比较方式以比较器为主。
怎么去定义一个比较器呢?
1,定义一个类,实现Comparator接口;
2,复写compare方法;
3,将比较器对象作为参数传递给集合的构造函数。
用代码进行演示:
/*
需求:将学生对象存进TreeSet集合中,对学生对象按姓名进行排序。
*/
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
int num = new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyCompare());
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi02",21));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi007",29));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class MyCompare implements Comparator//定一一个比较器
{
public int compare(Object o1,Object o2)//复写compare方法
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());//按照姓名进行比较
if(num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
打印结果是:
泛型
概述:泛型是JDK1,5以后出现的新特性,用于解决安全问题,是一个安全机制(类型安全机制)。
在泛型出现以前,我们通过定义Object来接收任意类型的参数,然而这种方式带来的缺点是要做强制的类型转换,如果要进行强制类型转换,我们需要提前知道实际参数类型是什么,才能进行转换,而且对于类型转换错误这种异常,在编译时期,编译器可能不提示错误,在运行时才出现,这样就有安全隐患。
泛型出现后的好处:1,将运行时起出现的问题ClassCastException转移到了编译时
期,方便与程序员解决问题,让运行时期的安全问题减少;
2,避免了强制转换的麻烦。
用代码来演示:
import java.util.*;
class GenericDemo
{
public static void main(String[] args)
{
ArrayList<String> al = new ArrayList<String>();//尖括号内放的就是我们限定的只能装到集合中的元素;
al.add("adadada");
al.add("dfgergre");
al.add("gerdfdf");
al.add("bhgfht");
Iterator<String> it = al.iterator();//迭代器中设置泛型;
while(it.hasNext())
{
String s = it.next();//不用再做强制转换;
System.out.println(s+":::"+s.length());
}
}
}
发现编译时这个不安全操作的提示消失了,而且我们也不用在做强制类型转换。
泛型的应用
格式:通过< >来接收要操作的引用数据类型。
在java提供的对象时,什么时候写泛型?
通常在集合框架中很常见,只要见到< >就要定义泛型。
Collection<E>,E没有任何意义,相当于形式参数,一个变量,就是Element,元素,其实<>就是来接收类型的,当使用集合时,将集合中要存储的数据类型作为参数,传递到<>中即可,如同函数中传参数一样。
注意:我们在上边对对象进行比较的equals方法,复写的是Object方法,Object没有泛型,所以那个Object必须写,对象也必须要做强转。
泛型类
集合的迭代器,比较器都涉及到泛型了,我们也可以在自己定义的类中使用泛型,以前我们都是用Object来接收任意类型的参数,现在我们可以通过泛型来完成。
接下来用代码进行演示:
class Worker
{
}
class Student
{
}
//泛型前做法。
class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj = obj;
}
public Object getObject()
{
return obj;
}
}
//泛型类
class Utils<QQ>//这就是个泛型类
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}
class GenericDemo3
{
public static void main(String[] args)
{
Utils<Worker> u = new Utils<Worker>();
u.setObject(new Student());
Worker w = u.getObject();//在这里,定义泛型后,不需要再做强转
}
}
那么我们在什么时候要定义泛型呢?
当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展(基本数据类型不确定,定义不了),泛型能把运行时的错误转移到编译时期,也避免了类型的强转,集合就是泛型类。
泛型方法
通过分析,我们发现,泛型类是有局限性的,对象一固定,要操作的类型就确定了,泛型类的对象明确要操作的具体数据类型后,所有方法要操作的类型就已经固定了,为了让不同的方法操作不同的数据类型,而且类型还不确定,那么可以将泛型定义到方法中。
泛型定义在方法上,放到返回值类型前边,修饰符的后边。
特殊之处:静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,可以将反省定义在方法上。
泛型接口
将泛型定义在接口上,用代码演示下吧:
//泛型定义在接口上。
interface Inter<T>
{
void show(T t);
}
class InterImpl implements Inter<String>//实现此接口时已明确要操作的类型是String;
{
public void show(String t)
{
System.out.println("show :"+t);
}
}
class InterImpl<T> implements Inter<T>//实现此接口时也不明确要操作的类型;
{
public void show(T t)
{
System.out.println("show :"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl<Integer> i = new InterImpl<Integer>();
i.show(4);
//InterImpl i = new InterImpl();
//i.show("haha");
}
}
泛型限定
泛型限定是用于泛型扩展用的。
泛型限定有两个限定:向上限定和向下限定。
?:通配符,也可以理解为占位符,不明确具体类型时用"?"表示,使用?后,就不能在使用传进来类型的对象的特有方法了,因为类型不明确,该类型对应的对象能调用的方法也是不明确的。
? extends E:向上限定,可以接受E或者E的子类型。
? super E:向下限定,可以接受E或者E的父类型。
Map集合
特点:该集合存储的是键值对,一对一对往里存,而且要保证该集合键的唯一性。
常见的子类
Hashtable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的,jdk1.0出现,效率低。
HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的,将hashtable替代,jdk1.2出现,效率高。
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
常用方法
添加
put(K key,V value):如果添加相同的键,后添加的值会覆盖原有键对应值,返
回被覆盖的值;
putAll(Map <? extends K,? extends V> m):添加一个集合;
删除
clear():清空
remove(Object key):删除指定键值对;
判断
containsKey(Object key):判断键是否存在;
containsValue(Object value):判断值是否存在;
isEmpty():判断是否为空;
获取
get(Object key):通过键获取对应的值;
size():获取集合的长度;
values():获取Map集合中所有值,返回一个Collection集合;
从集合中取出元素的方法:keySet(),entrySet()---重点内容
keySet:key键,Set集合,将map集合中所有的键存入到了set集合,因为set集合具备迭代器,所以可以根据迭代器取出所有的键,然后根据键get方法获取所有的值。
原理:将map集合转成set集合,在通过迭代器取出。
entrySet:将map集合中的映射关系存入到set集合中,而这个关系的数据类型就是:Map.Entry,Entry其实就是Map中的一个static内部接口。
将它定义在内部的原因就是:只有有了Map集合,有了键值对,才会有键值的映射关系,关系属于Map集合中的一个内部事物,而且该事物在直接访问Map集合中的元素,然后在使用getValue和getKey方法获取值和键。
练习:每一个学生都有对应的归属地,学生student,地址String,每一个学生都有自己的名字和年龄,同姓名同年龄的视为同一个学生,要保证学生的唯一性,并对学生年龄对象进行升序排序。
/*
需求:每一个学生都有对应的归属地,学生student,地址String,每一个学生都有自己的名字和年龄
同姓名同年龄的视为同一个学生,要保证学生的唯一性,并使用比较器对学生对象的年龄进行升序排序。
步骤:
1,描述学生对象;
2,因为学生是以键形式存在的,所以可以把学生键用TreeMap集合进行存储;
3,获取TreeMap集合中的元素。
*/
import java.util.*;
class Student implements Comparable<Student>//实现Comparable接口,让学生具备比较性
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name+":::"+age;
}
public int hashCode()
{
return name.hashCode()+age*34;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("不是学生类");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public int compareTo(Student s)//复写compareTo方法,自定义比较内容
{
int num = this.name.compareTo(s.name);
if(num==0)
return new Integer(this.age).compareTo(new Integer(s.age));
return num;
}
}
class MapTest
{
public static void main(String[] args)
{
Map<Student,String> tm = new TreeMap<Student,String>(new MyComp());//将学生对象存入TreeMap中;
tm.put(new Student("zhangsan",23),"beijing");
tm.put(new Student("lisi",21),"shanghai");
tm.put(new Student("wangwu",31),"shenzhen");
tm.put(new Student("zhaoliu",17),"wuhan");
tm.put(new Student("zhouqi",18),"tianjin");
/*
方法一:用entrySet方法取出集合中的键值;
Set<Map.Entry<Student,String>> ts = tm.entrySet();
Iterator<Map.Entry<Student,String>> it = ts.iterator();
while(it.hasNext())
{
Map.Entry<Student,String> me = it.next();
Student str = me.getKey();
String addr = me.getValue();
System.out.println(str+"="+addr);
}
*/
//方法二:用keySet方法取出集合中的键值;
Set<Student> ts = tm.keySet();
Iterator<Student> it = ts.iterator();
while(it.hasNext())
{
Student str = it.next();
String addr = tm.get(str);
System.out.println("姓名:"+str.getName()+",<span style="white-space:pre"> </span>年龄:"+str.getAge()+"----家庭地址:"+addr);
}
}
}
class MyComp implements Comparator<Student>//自定义比较器
{
public int compare(Student s1,Student s2)
{
int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
if(num==0)
return s1.getName().compareTo(s2.getName());
return num;
}
}
运行的结果是:
Map扩展知识:一对多,原本把学生的id和姓名也作为键值对,发现可以直接把这两个属性封装成学生对象,把房间名和学生对象作为键值对传到map集合中,然后不同的学生对象放在List集合中。
用代码来体现:
import java.util.*;
class Student
{
private String name;
private int id;
Student(String name,int id)
{
this.name = name;
this.id = id;
}
public String toString()
{
return name+".."+id;
}
}
class MapTest
{
public static void main(String[] args)
{
Map<String,List<Student>> hm = new HashMap<String,List<Student>>();//Map集合中还有List集合;
List<Student> yure = new ArrayList<Student>();//预热班,放的是预热班的学生;
List<Student> jiuye = new ArrayList<Student>();//就业班,放的是就业班的学生;
hm.put("yure",yure);//将预热班教师名称作为键,预热班学生集合作为值存到Map集合中;
hm.put("jiuye",jiuye);//将预热班教师名称作为键,预热班学生集合作为值存到Map集合中;
yure.add(new Student("zhangsan",1));//将学生放到预热班集合中;
yure.add(new Student("lisi",3));
jiuye.add(new Student("wangwu",3));
jiuye.add(new Student("zhaoliu",2));
Set<String> keySet = hm.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext())//取出教师名称和对应的学生对象
{
String roomName = it.next();
List<Student> room = hm.get(roomName);
System.out.println(roomName);
Iterator<Student> it1 = room.iterator();
while(it1.hasNext())
{
Student str = it1.next();
System.out.println(str);
}
}
}
}
运行结果是:
|
|