集合总结:
在集合中有两个接口是非常重要的,即Collection和Map;在这两个集合的基础上,又有一些完成特定功能
的其它子集合和实现类,下面就详细介绍一下其中非常重要的。
下面代码是在API1.6版本下完成的,以下学习中的方法介绍请参考API
Collection :java.util包中
|--Set
元素是无序的,所谓无序即不经其它处理,存入顺序和取出顺序是不同(因为底层的不同);
元素不重复。
|--List
元素有序
元素可重复
Collection中的方法是共有的方法,其中应该熟练掌握的有:
对这些方法不在给予单独的介绍,在以下例子中用到时会有详细注释
增加:
boolean add(E e);
boolean addAll(Collection<? extends E> c);
删除:
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
判断:
boolean isEmpty();
boolean contains(Object o);
boolean containsAll(Collection<?> c);
其它常用: int size();Iterator<E> iterator();//迭代是遍历集合非常常用的
还有就是转换成数组
Set
|--HashSet
底层数据结构是哈希表,实现不同步,可以存储null;
遍历:
迭代器:是遍历集合的很好的方式,每个集合类中都有iterator方法,这是为了遍历的需求;
高级for循环:能用迭代器遍历的,都能用高级for循环进行遍历;
不重复:其特性是依赖于其底层实现结构,哈希表;在添加元素时,会进行比较,如果不相同,下添加
比较方式:1、首先比较其哈希值是否相同;2、若哈希值相同,再比较其存储对象的内容是否相同
这种比较方式是默认调用的
注意:HashSet方法中的用到查找的方法如contains(),remove()等,都依赖于以上两种比较方式,所以
对于自定义类型,一般要重写hashCode()和equals()方法(底层基于哈希表的都是如此)。
在HashSet的例子中会对以上重写方法进行详细介绍,以后不再重复
|--TreeSet
底层数据结构是二叉树,实现不同步
遍历:和HashSet的遍历方式相同;
元素默认按自然顺序排序:对于自定义类型一般
1、重写Comparable接口中的compareTo()方法让元素本身具有比较性;
2、或者在定义集合时,传入参数比较器,比较器要实现Comparator接口中的compare()方法
当两种方式都存在时,以第二种方式为主。
注意:当类中已经写过compareTo()方法,但其比较方式不是自己想要的,这时一般不是去重写改写
该方法,而是定义一个比较器,这在开发中是很常见的
无重复:在进行添加时会排序,调用比较方法,当内容相同时就不在添加
List
该集合进行有关查找,匹配的操作时,用到的是equals(),方法,所以一般要重写该方法
凡是用到索引操作的都是该集合特有的方法
|--Vector
底层数据结构是可变长度数组,jdk1.0 线程同步,相对ArrayList,效率低,功能几乎相同,逐步被ArrayList取代
长度初始10,100%增长
枚举是Vector中特有方法,Enumeration elments()和Iterator方法相同,但有限考虑迭代器方法
遍历:索引、迭代器、枚举、高级for循环
|--ArrayList
底层可变长度数组,jdk1.2 实现不同步,大致等同于Vector中的方法
长度初始10,50%增长
遍历:索引、迭代器、高级for循环
|--LinkedList
底层是链表,可以方便的模拟栈和队列
遍历:索引,迭代器,高级for循环
set集合特有方法:ListIterator<E> listIterator(int index),列表迭代器,其中提供了操作
普通迭代器Iterator:在进行迭代操作时,不能进行集合操作,否则抛出异常ConcurrentModificationException
所以迭代时,只能进行迭代方法的操作,不能进行添加,修改等。对于迭代器中的remove()方法,操作也有局限性,
如:每调用一次next()方法,只能进行一次remove()操作,且必须和next()共同使用
ListIterator:在该迭代器实现中提供了一些对集合操作的方法
void add(E e); //添加
void remove();//删除
void set(E e); //修改
boolean hasPrevious(); //当前指向前一个是否有元素,逆向遍历
int nextIndex();//当前指向下一个元素索引
E previous();//
int previousIndex();
这些方法使对集合的操作更加方便
LinkedList中还提供了特别的方法:这也可以很方便的模拟栈和队列
addFirst();
addLast();
//获取元素,不删除
getFirst();//列表是 isEmpty 则抛出异常NoSuchElementException
getLast();
//获取元素,删除元素
removeFirst();
removeLast();
jdk 1.6出现
offerFirst();
offerLast();
peekFirst(); isEmpty 不抛异常,返回null
peekLast();
poolFirst(); //isEmpty 不抛异常,返回null
poolLast();
//HashSet练习
import java.util.*;
public class Test
{
public static void main(String[] args){
simApp();
//operatePerson();
}
/*
简单的应用 其方法可以参见API,方法的应用其实很简单
对于其方法应该熟练掌握的有
下面牵涉到泛型,这个是jdk1.5之后新出的特性,是为了程序的健壮性,在定义集合时,声明什么样的类型
就只能存储什么类型;当没有声明要存储什么类型时在编译时会有警告,能编译通过,但是在执行时可能会出错,
所以一般都会加上泛型(关于泛型的详细介绍将在其他博客中详细介绍)
*/
public static void simApp(){
无参构造,String类型 泛型类型String
HashSet<String> hs = new HashSet<String>();
hs.add("zhangsan"); ///添加元素
hs.add("lisi");
hs.add("zhangsan");
hs.add(null); //HashSet中可以存储 null
System.out.println(hs.size());
/**
迭代器是取出集合中元素的有效方式:在每个结合中都有 iterator()方法,在Iterator接口中有三个方法
boolean hasNxet() 判断是否还有元素;
E next()取出当前指针指向的元素,每执行一次,指针向后移动一位
void remove()移除迭代器中当前指针指向的元素
但迭代器操作有局限性,在介绍LinkedList时会说明不同
*/
/*for (Iterator<String> it = hs.iterator(); it.hasNext();)
{
String str = it.next();
System.out.println(str);
}*/
///高级for循环进行遍历
for (String s : hs)
{
System.out.println(s);
}
//输出结果为:null lisi zhangsan 这也说明了Set集合的两个特性,无序,去重
boolean flag = hs.remove("张三");//boolean remove(Object) 移除单个元素
}
//往hashSet中添加自定义对象时
public static void operatePerson(){
HashSet<Person> hs = new HashSet<Person>();
hs.add(new Person("zhangsan", 30));
hs.add(new Person("lisi", 25));
hs.add(new Person("zhangsan", 40));
for (Iterator<Person> it = hs.iterator(); it.hasNext();)
{
Person p = it.next();
System.out.println(p);
}
}
}
/**
对于自定义类型,一般书写时要重写toString()方法,这也是为了便于输出操作
在下面这个Person类中,重写了hashCode()、equals() 和 toString()三个方法
*/
class Person
{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
//重写hashCode(),在此重写的目的就是让不同对象hashCode值尽量不同,这个值可以任意写,但是为了尽量让其
//不同,用如下方式
public int hashCode(){
return name.hashCode() + age*37;
}
//在此是重写Object类中的equals方法
public boolean equals(Object obj){
//instanceof 是关键字 ,用于判断传入的类型是否匹配
if (!(obj instanceof Person))
{
throw new RuntimeException("类型不匹配");
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String toString(){
return ("name:" + name + "---age:" + age);
}
}
//TreeSet练习
import java.util.*;
class Person implements Comparable<Person>
{
private String name;
private int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
//实现copareTo方法 姓名 年龄升序;在此我是通过调用compareTo方法,也可以不调用,自己写
public int compareTo(Person p){
int num = name.compareTo(p.name);
//如果姓名相同,则比较年龄
if (num == 0)
{
return new Integer(age).compareTo(new Integer(p.age));
}
return num;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String toString(){
return "name:" + name + "---age:" + age;
}
}
//定义迭代器 姓名 年龄降序, 由于只有写了这一个方法,所以可以定义为内部类
class Cmp implements Comparator<Person>
{
public int compare(Person p1, Person p2){
int num = p2.getName().compareTo(p2.getName());
if (num == 0)
{
return new Integer(p2.getAge()).compareTo(p1.getAge());
}
return num;
}
}
public class Test
{
public static void main(String[] args){
//无参构造函数
//TreeSet<Person> ts = new TreeSet<Person>();
//带比较器的构造函数
TreeSet<Person> ts = new TreeSet<Person>(new Cmp());
ts.add(new Person("zhangsan", 30));
ts.add(new Person("lisi", 23));
ts.add(new Person("zhangsan", 30));
ts.add(new Person("lisi", 18));
for (Iterator<Person> it = ts.iterator(); it.hasNext();)
{
Person p = it.next();
System.out.println(p);
}
/**
没有调用比较器时 输出结果
name:lisi---age:18
name:lisi---age:23
name:zhangsan---age:30
*/
/*
带比较器的构造函数
name:zhangsan---age:30
name:lisi---age:23
name:lisi---age:18
*/
}
}
//Vector练习
/**
枚举方法虽然不是常用,但是在一些地方还是会用到,在此只介绍枚举的用法
*/
import java.util.*;
public class Test
{
public static void main(String[] args){
Vector<String> v = new Vector<String>();
//添加元素
v.add("zhangsan");
v.add("lisi");
v.add("aisi");
v.add("zhangsan");
/*
Enumeration接口中有两个方法
boolean hasMoreElements();判断是否还有元素,相当于迭代器中的hasNext()
E nextElements();取出下一元素,相当于next();
*/
Enumeration<String> e = v.elements();
for (; e.hasMoreElements(); )
{
String str = e.nextElement();
System.out.println(str);
}
/*
在一些特殊地方需要用到枚举方法,需要用Vector进行存储,但是Vector效率不高,所以需要用其它的
集合,但要自己实现Enumeration中的方法
*/
ArrayList<String> al = new ArrayList<String>();
al.add("zhangsan");
al.add("lisi");
al.add("aisi");
al.add("zhangsan");
Enumeration<String> e1 = iToe(al.iterator());
for (; e1.hasMoreElements(); )
{
String str = e1.nextElement();
System.out.println(str);
}
}
//将迭代器转成枚举 在内部类中访问本地变量,需要被声明为最终类型,所以加上final
public static Enumeration<String> iToe(final Iterator<String> it){
return new Enumeration<String>(){
public boolean hasMoreElements(){
return it.hasNext();
}
public String nextElement(){
return it.next();
}
};
}
}
//LinkedList练习
import java.util.*;
class Person
{
private String name;
private int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
//覆盖equals方法
/*public boolean equals(Object obj){
if (!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age; //equals此处的equals是字符串比较的
}*/
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String toString(){
return "name:" + name + "---age:" + age;
}
}
public class Test
{
public static void main(String[] args){
//simApp();
mulPerson();
}
//基本操作
public static void simApp(){
LinkedList<String> ll = new LinkedList<String>();
ll.add("zhangsan");
ll.add("lisi");
ll.add("zhangsan");
for (Iterator<String> it = ll.iterator(); it.hasNext(); )
{
//it.next();
//it.remove(); //每调用一次next()方法,只能调用一次remove()方法
//ll.add("fda"); //在迭代时,不能进行集合相关的操作,会发生异常
}
}
//添加自定义类型
public static void mulPerson(){
ArrayList<Person> oa = new ArrayList<Person>();
oa.add(new Person("zhangsan", 12));
oa.add(new Person("lisi", 13));
oa.add(new Person("wang", 12));
oa.add(new Person("zhangsan", 12));
Person pe = new Person("zhangsan", 12);
//当Person类中没有重写equals()方法时,该操作不起作用,当写过后,该方法移除第一次查找到的元素,
//对于后面有重复的,则不再操作
boolean flag = oa.remove(pe);
for (Iterator<Person> it = oa.iterator(); it.hasNext(); )
{
Person p = it.next();
System.out.println(p.getName() + ":" + p.getAge());
}
}
}