集合类出现的原因
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
集合中存储的是对象所在堆内存中的地址值,数组也是如此。
数组和集合类的区别
数组虽然也可以存储对象,但长度是固定的;
集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
集合框架的构成及分类
为什么会出现这么多的容器呢?
因为每个容器对数据的存储方式不同,这个存储方式称之为:数据结构
Collection定义了集合框架的共性功能。
1,添加
boolean add(e);添加对象
boolean addAll(collection);添加传入的集合中的所有元素
2,删除
boolean remove(e);删除对象
boolean removeAll(collection);删除传入集合中的所有元素
void clear();清空集合
3,判断
boolean contains(e);判断是否包含该对象
boolean isEmpty();判断该集合是否为空
4,获取
Iterator iterator();迭代器:集合中取出元素的方式
int size();获取该集合中元素的个数
5,获取交集
boolean retainAll();
6,集合变数组
Object[] toArray();
代码示例:
/**
Collection方法演示
*/
import java.util.*;
class CollectionDemo
{
public static void main(String[] args)
{
//用Collection子类ArrayList创建集合容器
ArrayList al1 = new ArrayList();
ArrayList al2 = new ArrayList();
//添加元素
al2.add("java01");
al2.add("java02");
al1.add("java01");
al1.add("java02");
al1.add("java03");
al1.add("java04");
//删除元素
al1.remove("java03");
sop(al1);
al1.removeAll(al2);
sop(al1);
//判断集合
sop(al1.isEmpty());
sop(al1.contains(al2));
//获取
sop(al1.size());
Iterator it = al1.iterator();
while (it.hasNext())
{
sop(it.next());
}
//取交集
sop(al1.retainAll(al2));
//集合变数组
Object[] obj = al2.toArray();
for (int a = 0;a<al2.size() ;a++ )
{
sop(obj[a]);
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
迭代器Iterator的说明
JAVA中有多种容器,因为每种容器的数据结构不同,所以取出对象的动作细节也不同,他们各自都有自己的取出方式,这些取出方式被定义在集合的内部,所以这个取出方式可以直接访问集合内部的元素。这些取出方式都有共性的内容,判断和取出,被定义在集合中的内部类都符合一个规则,该规则就是Iterator,内部类对外提供了一个公共的方法iterator();
举例说明:
电玩城里面抓娃娃的机器,装娃娃的箱子相当于是一个容器,里面的娃娃就是一个个对象,箱子里面抓娃娃的夹子就是迭代器,他被封装在容器的内部,外面的操纵杆是对外暴露的方法
Iterator的两种方式
/**
Iterator的两种定义方式
*/
import java.util.*;
class IteratorDemo
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
get1(al);
get2(al);
}
//方式一: while循环
public static void get1(ArrayList al)
{
Iterator it = al.iterator();
while (it.hasNext())
{
sop(it.next());
}
}
//方式二:for循环,使用这种结构,节省内存
public static void get2(ArrayList al)
{
for (Iterator it = al.iterator();it.hasNext() ; )
{
sop(it.next());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
Collection集合体系
Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
数组结构和链表数据结构说明
数组数据结构
查询块,是因为该数据结构中每个元素都有指定的角标记录,只要知道这角标就可以查到该元素;
增删慢,是因为每加入一个元素,其后面的元素都要向后面移动位置
图示:
链表数据结构
增删块,是因为该数据结构中每个元素都记住它前面的一个元素。删除元素时,数据结构中其实是这样的操作,断开这个元素指向的前一个元素,再断开它后面指向它的元素,最后将它后面的元素指向它前面的元素即可;
查询慢,是因为该数据结构中的元素只知道它前面的元素,除非你找到与之关联的元素,否则就要一直找下去
图示:
List特有的方法:凡是可以操作角标的方法都是该体系特有的方法
增 add();addAll(index,collection);
删 remove(index);
改 set(index,element);
查 get(index);subList(from,to);int indexOf(obj);ListIterator();
ListIterator()说明:
List集合特有的迭代器。ListIterator是Iterator的子接口。在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。所以,在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取。
ListIterator接口的特有方法
Boolean hasPrevious():
逆向遍历元素,和hasNext()方法相反
int nextIndex()
返回对 next 的后续调用所返回元素的索引。
E previous()
返回列表中的前一个元素。
int previousIndex()
返回对 previous 的后续调用所返回元素的索引。
void remove()
从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。
void set(E e)
用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。
代码示例:
/**
List集合的特有方法演示
*/
import java.util.*;
class ListDemo
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
al.add("java05");
print(al);
//删除元素
al.remove(2);
sop(al);
//修改元素
al.set(2,"java02");
sop(al);
get(al);
}
//获取元素
//方式一
public static void print(ArrayList al)
{
for (int a = 0;a<al.size() ;a++ )
{
sop("al"+a+"="+al.get(a));
}
}
//方式二
public static void get(ArrayList al)
{
ListIterator li = al.listIterator();//list集合特有的迭代器
while (li.hasNext())
{
sop(li.next());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
枚举
枚举是vector特有的取出方式;
其中的Enumeration和Iterator用法一致;
Vector和ArrayList的区别也就在此,Vector支持枚举。
代码示例:
/** Enumeration演示 */ import java.util.*; class EnumerationDemo { public static void main(String[] args) { Vector v = new Vector(); v.add("java01"); v.add("java02"); v.add("java03"); v.add("java04"); v.add("java05"); enumeration(v); } public static void enumeration(Vector v) { for (Enumeration en = v.elements();en.hasMoreElements() ; ) { System.out.println(en.nextElement()); } } }
LinkedList的特有方法
addFirst();在所有元素的最前面添加元素
addLast();在所有元素的最后面添加元素
getFirst();获取第一个位置的元素
getLast();获取最后一个位置的元素
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
removeFirst();获取第一个元素,并删除掉此元素
removeLast();获取最后一个元素,并删除掉此元素
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了替代方法。
以后使用这些方法
offerFirst();在集合的开头插入元素
offerLast();在集合的最后插入元素
peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。
pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
代码示例:
/**
LinkedList特有方法演示
*/
import java.util.*;
class LinkedListDemo
{
public static void main(String[] args)
{
LinkedList link = new LinkedList();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
link.addFirst("java04");
sop(link);
link.addLast("java01");
link.addLast("java02");
link.addLast("java03");
link.addLast("java04");
sop(link);
sop(link.getFirst());
sop(link.getLast());
sop(link.removeFirst());
sop(link.removeLast());
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
JDK1.6版本
/**
LinkedListJDK1.6 特有方法演示
*/
import java.util.*;
class LinkedListDemo
{
public static void main(String[] args)
{
LinkedList link = new LinkedList();
link.offerFirst("java01");
link.offerFirst("java02");
link.offerFirst("java03");
link.offerFirst("java04");
sop(link);
link.offerLast("java01");
link.offerLast("java02");
link.offerLast("java03");
link.offerLast("java04");
sop(link);
sop(link.peekFirst());
sop(link.peekLast());
sop(link.pollFirst());
sop(link.pollLast());
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
练习总结:
练习一
使用LinkedList模拟一个堆栈或者队列数据结构。
/**
使用LinkedList模拟一个堆栈或者队列数据结构。
堆栈:先进后出 如同一个杯子。
队列:先进先出 First in First out FIFO 如同一个水管。
*/
import java.util.*;
/*
此类将linkedList方法封装进我们自己创建的对象中;
实际开发中这种用法非常多见
*/
class DuiLie
{
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
public void myAdd(Object obj)
{
link.addFirst(obj);
}
/*
将此处的removeLast改成removeFirst方法,
就是先进后出的,堆栈数据结构
*/
public Object myGet()
{
return link.removeLast();
}
public boolean isNull()
{
return link.isEmpty();
}
}
class DuiLieTest
{
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());
}
}
}
总结:
练习一可以直接使用LinkedList集合完成,但实际开发中,这种方法并不适用。实际开发中,都是将其封装起来,定义我们自己的名称,对外暴露自己设定的方法,增强通用性。
这一思想非常重要
练习二:
删除集合中的重复元素
/**
需求:删除ArrayList集合中的重复元素
分析:
1,建立一个临时容器,先放入一个元素
2,放入之后每放入一个元素就和其中的元素记性比较,如果相同则不存入,否则存入
3,输出该集合
步骤:
1,临时容器al,放入元素al.add();
2,遍历容器中的数组:Iterator(),判断元素是否存在:contains(),不同存入add()
3,sop(al)
*/
import java.util.*;
class RemoveRepeatTest
{
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");
sop(al);//输出al集合中的元素
al = removeRepeat(al);//删除集合al中的重复元素
sop(al);//输出取出重复元素后的集合
}
public static ArrayList removeRepeat(ArrayList al)
{
ArrayList newAl = new ArrayList();//建立临时容器,用于存储未重复的元素
/*
遍历集合al中的元素,将元素存入临时容器newAl中,判断临时容器中是否有该元素,
如果没有就存入。
注意:一个hasNext()只能对应一个next();
*/
for (Iterator it = al.iterator();it.hasNext() ; )
{
Object obj = it.next();//一个hasNext()只能对应一个next(),所以设置一个引用类型变量进行存储
if (!(newAl.contains(obj)))//判断这个集合中是否包含这个元素
{
newAl.add(obj);
}
}
return newAl;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
练习三:
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
/**
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。
思路:
1,存储元素
2,删除重复元素
3,输出元素
步骤:
1.定义Person类,该类中具有getName方法和getAge方法,复写equals方法
2.定义一个临时容器,用于存储未重复的元素,判断临时容器中是否包含该元素,不包含则存储,否则不存储
3,输出临时容器
*/
import java.util.*;
class MyTest
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
/*
这里有一个自动向上转型的过程,Person对象向上转型为object对象
因为add()方法中添加的是object对象,这里存入person对象,相当于
Object obj = new Person("zhangsan01",11);
父类引用指向子类对象,多态的表现
*/
al.add(new Person("zhangsan01",11));
al.add(new Person("lisi01",22));
al.add(new Person("zhangsan02",22));
al.add(new Person("lisi01",22));
al.add(new Person("zhangsan03",43));
al = removeRepeat(al);
iterator(al);
}
//遍历集合中的对象,
public static void iterator(ArrayList al)
{
for (Iterator it = al.iterator();it.hasNext() ; )
{
/*
it.next()中取出的是Object对象,要对person进行操作,
需要将Object对象强制转换成Person对象
*/
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
//判断临时容器中是否存在相同的元素,不同的存储 ,相同的不进行存储
public static ArrayList removeRepeat(ArrayList al)
{
ArrayList newAl = new ArrayList();
for (Iterator it = al.iterator();it.hasNext(); )
{
Object obj = it.next();
/*
注意:contains()方法底层调用的方法是equals()方法
在执行contains方法时,默认调用equals方法
*/
if (!(newAl.contains(obj)))
{
newAl.add(obj);
}
}
return newAl;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
/*
Object中的equals比较的是对象的地址值,这里覆写对象的equals方法,
使其具备判断对象的姓名和年龄是否相同的功能
*/
public boolean equals(Object obj)
{
//不包含就不进行判断
if (!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;//Object对象强转成Person对象
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()//该方法主要用于迭代集合中对象的内容时,被调用
{
return name;
}
public int getAge()
{
return age;
}
}
程序知识点总结:
1,存储元素和存储对象是两个不同的概念
对元素进行操作的过程相对较简单
对对象进行操作的过程中需要对对象进行强制转换,因为集合中涉及到的方法,传入的都是Object对象(例如add(Object obj)),所以,如果要对子类对象进行操作,需要将该对象进行强制向下转型;
2,contains()方法和remove()方法底层调用的都是equals()方法,这点非常重要;
这也是remove方法的返回值类型是Boolean型的原因