一、什么是集合框架
在Java API中专门设计了一组类,这组类的功能是实现各种方式的数据存储,这样一组专门用来存储其他对象的类,就称为对象容器类,这组类和接口的设计结构也被统称为集合框架。
下面一张图可以清晰的说明这组类的关系。
从上图可以看出,容器类分两个阵营,Collection为元素集合,而Map为映射关系集合。
我们先总结Collection接口阵营的类。
1、Collection接口
毕老师说过,容器类的方法就四种,增删查改
所以Collection里共性的方法有:
1)add(Object obj)往里面增加元素
addAll(Collection ct) 往里面增加集合ct的全部元素
2)remove(Object obj)删除obj元素
removeAll(Collection ct) 删除集合ct所以元素
clear() 清空集合里所以元素
3)boolean contains(e) 判断结合是否包含e元素
这里还有一个很特殊的方法,因为Collection没有提供获取元素的方法,它只提供了一个迭代器,来迭代返回元素。
iterator()方法返回一个Iterator对象,来对容器进行迭代。
迭代器里面有的方法
hasNext() 判断游标右边是否有元素
next() 返回游标右边的元素并将游标移动到下个位置
remove()删除游标左边的元素
Collection接口又分为List接口和Set接口。
二、List接口
LIst接口有3个常见的实现类。分别是ArrayList,LinkList,Vector。
ArrayList:底层的数据结构时数组结构
特点:查询速度很快,因为有角标,但增删速度稍慢,线程不同步
LinkedList:底层使用的是链表数据结构
特点:增删速度很快,但查询速度稍慢,因为每一个元素都链接到前一元素。
Vector:底层是数组结构
特点:增删查询都很慢,被ArrayList替代了,线程是同步的。
由于ArrayList是最常用的,它跟数组差不多,而且有角标,所以它有很多自己独有的增删查改的方法。
1)add(int index,e) 在指定位置增加给定的元素
addAll(int index,Collection) 在指定位置增加给定集合中的所有元素,若省略位置参数,则在当前集合的后面依次添加元素
2)remove(int index) 删除集合中指定位置上的元素
3)get(int index) 获取指定位置上的元素
indexOf(e) 通过指定元素获取其在集合中的位置
4)set(int index,e)把index角标的元素替换成e
这里需要提一点就是List他有自己的迭代且ListIterator。是Iterator的子接口。
下面是一个毕老师的关于ArrayList的代码示例。
class ListDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
methodAdd();
//methodListIterator();
}
public static void methodAdd()
{
//创建一个集合容器,使用Collection接口的子类,ArrayList
ArrayList list = new ArrayList();
//1.添加元素--->add(Object obj),多态
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java04");
ArrayList list2 = new ArrayList();
//1.添加元素--->add(Object obj),多态
list2.add("java05");
list2.add("java06");
list2.add("java07");
list2.add("java08");
//打印原集合
sop("原集合:" + list);
sop("------------------");
//1.在某一个位置上添加元素:add(int index,"新元素")
list.add(1,"java001");
sop("增加后的集合:" + list);
sop("---------");
list.addAll(1,list2);
sop("在list中1位置后添加list2:" + list);
sop("------------------");
//2.删除指定位置上的元素:
list.remove(2);
sop("删除后的集合:" + list);
sop("------------------");
//3.改变某一位置上的元素:set(int index,"要改成的元素")
list.set(2,"java007");
sop("改变角标为2的元素后的元素:" + list);
sop("------------------");
//4.获取元素:get()
list.get(1);
sop("获取角标为1上的元素:" + list.get(1));
sop("------------------");
//通过某个元素获取其在集合中的位置--indexOf("查找的元素")
int m = list.indexOf("java007");
sop("获取“java007”所在的位置:" + m);
//获取从某个位置到另一位置上的元素subList()
List l = list.subList(1,3);
sop("获取从位置1到3上的元素:" + l);
sop("------------------");
//4.获取全部元素
//get方法的for循环
sop("get方法:");
for (int i=0;i<list.size();i++)
{
sop("list(" + i + ")" + list.get(i));
}
sop("------------------");
//迭代器方法:Iterator()
for (Iterator it = list.iterator();it.hasNext(); )
{
sop("next:" + it.next());
}
sop("------------------");
}
public static void methodListIterator()
{
//演示列表迭代器:
ArrayList list = new ArrayList();
//1.添加元素--->add(Object obj),多态
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java04");
//打印原集合
sop("原集合:" + list);
sop("------------------");
//在迭代过程中,准备添加或删除元素
for (ListIterator it = list.listIterator();it.hasNext(); )
{
Object obj = it.next();
if (obj.equals("java01"))
it.remove();
else if(obj.equals("java02"))
it.add("增加java200");
else if(obj.equals("java03"))
it.set("修改为java300");
sop("obj:" + obj);
}
sop("list :" + list);
}
}
LinkList和Vector用的频率不高,Vector更是被ArrayList所替代,这里就不过多介绍了。
三、Set接口
Set接口跟List接口最大的不同就是Set没有角标,而且元素不可以重复。有三个实现类,HashSet、LinkSet、TreeSet
1、HashSet类
底层数据结构时哈希表,且元素取出方式只有迭代器方法。
因为Set接口里面元素都不一样的,所以需要提供怎么才算重复的方法,里面提供了hashCode()和equals()方法来判断是否唯一的标准。
而且,HashSet里面的元素加入顺序和迭代顺序是不一样的,这也验证HashSet里面的元素是无序的。HashSet就先不实例了,下面就介绍TreeSet,基本掌握了TreeSet就掌握HashSet.。
2、HashSet和TreeSet
TreeSet和HashSet差不多,只不过TreeSet里多了一个比较方法来进行排序。而比较方式有两种,要么存进来的元素实现了Comparable接口,要么在创建TreeSet是加入一个Comparator比较器。如果两种方式都实现了,优先考虑比较器来进行比较。
下面一个一个例子
public class TheStudent implements Comparable {
private String name;
private int math;
private int cn;
private int es;
private int sum;
TheStudent(String name,int math,int cn,int es)
{
this.name=name;
this.math=math;
this.cn=cn;
this.es=es;
sum=math+cn+es;
}
public String toString()
{
return "Student:["+name+","+math+","+cn+","+es+","+sum+"]";
}
public int hashCode()
{
return this.name.hashCode()+5*sum;
}
public boolean equals(Object obj)
{
if(!(obj instanceof TheStudent))
throw new RuntimeException("类型不对");
TheStudent stu=(TheStudent)obj;
return this.name.equals(stu.name)&&this.sum==stu.sum;
}
public int compareTo(Object stu)
{
TheStudent a=(TheStudent)stu;
if(a.sum>this.sum)
return 1;
else if(this.sum==a.sum)
return this.name.compareTo(a.name);
return -1;
}
}
import java.io.*;
import java.util.*;
class FileStudent {
public static Set<TheStudent> inputStudents()
{
System.out.println("请输入学生信息:");
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String s=null;
Set stus=new TreeSet();
try
{
while((s=in.readLine())!=null)
{
if(s.equalsIgnoreCase("exit"))
{
System.out.println("安全退出。");
break;
}
String[] qiege=s.split(",");
stus.add(new TheStudent(qiege[0],
Integer.parseInt(qiege[1]),
Integer.parseInt(qiege[2]),
Integer.parseInt(qiege[3])));
}
return stus;
}
catch(Exception e)
{
throw new RuntimeException("输入出错");
}
finally
{
try
{
if(in!=null)
in.close();
}
catch(Exception e)
{
throw new RuntimeException(" 关闭不了");
}
}
}
public static void writeto(Set<TheStudent> e)
{
BufferedWriter bfw=null;
try
{
bfw=new BufferedWriter(new FileWriter("student.txt"));
for(TheStudent s:e)
{
bfw.write(s.toString()+"\t");
bfw.newLine();
bfw.flush();
}
}
catch(Exception a)
{
System.out.println("error!");
}
finally
{
if(bfw!=null)
try
{
bfw.close();
}
catch(Exception b)
{
}
}
}
}
这是一个比较综合的例子,里面有TreeSet的用法。
关于Map接口,这里就不过多介绍了,基本用法跟Set差不多,因为它里面的键就是用Set来存放的。只要保证键的唯一性就可以了,可以举一反三。