------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、集合框架概述
为什么会出现集合类:
对象用于封装特有的数据,对象多了就需要储存,如果对象的个数不确定,就用集合进行储存。
集合的特点:
1、集合只可以用于储存数据
2、集合是可变长度的
3、集合可以储存不同类型的对象
4、集合中储存的是对象的引用(地址),不可以储存数据类型值
集合和数组的区别:
1、集合是可变长度,数组是固定长度
2、集合只能储存对象,数组可以储存基本数据类型
3、集合可以储存不同数据类型,数组必须储存同一类型
为什么会有多个容器
因为每个容器对数据的储存方式不同,这种储存方式叫做数据结构。
二、Collection接口
Collection是框架的常用接口有List和Set两个常用的子接口
Collection:
|--List:有序(元素存入集合的顺序和取出的一致)元素都有索引,元素可以重复。
|--Set:无序(存入和取出顺序有可能不一致),不可以储存重复元素。必须保证元素的唯一性。
Collection接口中常用的方法
1、添加
add(Object):添加一个元素
addAll(Collection):添加一个集合中的所有元素
2、删除
clear():将集合中元素全部删除,清空集合。
remove(obj):删除集合中的指定对象,注意删除成功,集合的长度会改变。
removeAll(collection):删除部分元素。部分元素和传入Collection一致。
al1.removeAll(al2):删除a1中和a2中重复的元素。
3、判断
boolean contains(obj):集合中是否包含指定元素
boolean containsAll(Collection):集合中是否包含指定的多个元素
boolean isEmpty():集合中是否有元素
4、获取
in size():集合中有几个元素
Iterator iterator():取出元素中的所有元素,迭代器
5、取交集
boolean retainAll(Collection):对当前集合中保留和指定集合中相同的元素。如果两个集合元素相同,返回false;如果retainAll修改了当前集合返回true
7、将集合变为数组
toArray()
三、迭代器接口
什么是迭代器:
迭代器是一个接口。作用:用于取集合中的元素
(1)当取出这个动作不足以用一个函数来描述,需要用多种功能来体现,那么就把取出这个动作封装成一个对象,通过内部类来描述对象,这样可以直接访问集合内部的
元素。
(2)每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都具有共性内容: 判断和取出。那么就可以将这些共性抽取。
(3)这些内部类都符合一个规则,该规则是Iterator。如何获取集合的取出对象呢?通过一个对外提供的方法。Iterator();
(4)Collection中有iterator(),所以每一个子类集合对象都具备迭代器。
迭代器的常见操作:
hasNext():如果仍有元素可以迭代,则返回true
next():返回迭代的下一元素
remove():从迭代器指向的Collection中移除迭代器返回的最后一个元素
注意:迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException
在迭代时循环中使用一次next,就要hasNext判断一次
迭代器的next方法返回值类型是Object,要记得类型转换
public static void main(String[] args) {
//创建一个集合容器,使用Collection接口的子类,ArrayList
Collection coll = new ArrayList();
coll.add("abc0");
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//方法一
Iterator it = coll.iterator();//获取一个迭代器,用于取出集合中的元素。
while (it.hasNext()) {
System.out.println(it.next());
}
//方法二推荐使用
for(Iterator it = coll.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
四、List接口
List;有序,有索引,可重复
|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快,增删速度慢。
|--Linkedlist:底层数据结构是链表,线程不同步,增删元素的速度非常快。查询速度慢。
|--Vector:底层的数据结构就是数组,线程是同步的,Vector无论查询和增删都非常慢
List特有方法:
凡是可以操作角标的方法都是该体系特有的方法。
增:
add(index,element);//在指定的索引位置添加元素
addAll(index,Collection);//在指定位置添加集合元素
删:
remove(index);//删除指定位置的元素
改:
set(index,element);//修改指定位置的元素
查:
get(index);//获取角标元素
subList(from,to);//获取部分元素
listIterator();//通过迭代方法获取全部元素
indexOf(obj);//获取对象位置,如果没有该对象则返回-1
lastIndexOf(Object o):反向索引指定元素的位置
List subList(start,end):获取子列表
List集合因为角标有了自己的获取元素的方式:遍历
for(int x = 0;x<list.size();x++)
{
sop("get:"+list.get(x));
}
ListIterator是Iterator的子接口,是List集合特有的迭代器。
因为ListIterator的方法有限,同时不能通过集合对象的方法操作集合中的元素。否则会发生ConcurrentModificationException并发生异常。
所以可以通过ListIterator方法拓展对元素的操作。
ListIterator特有的方法
add(object);//增加
set(object);//修改为
hasPrevious();//逆向遍历,如果存在返回true
previous();返回列表中的前一个元素
枚举Enumeration:
就是Vector特有的取出方式。Vector有三种取出方式。
其实枚举和迭代是一样的。因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。
特有方法:
addElement(obj);//添加元素,相当于add(obj);
Enumerationelements();//Vector特有取出方式(枚举)
hasMoreElements();//相当于Iterator的hasNext()方法
nextElements();//相当于Iterator的next()方法
五、LinkedList
LinkedList底层使用的是链表数据结构。特点增删速度快查询慢
特有方法:
增加:
addFirst();//添加在头部
addLast();
删除:
removeFirst();//获取并删除链表中的第一个元素
removeLast();
获取:
getFirst()://获取不删除链表中的第一个元素如果链表为空,抛出NoSuchElementException
getlast();
在JDK1.6之后出现了替代方法
增加
offerFirst();
offerlast();
删除
pollFirst();//获取并删除链表中的第一个元素,如果链表为空返回null
pollLast();
获取
peekFirst();//获取链表中的第一个元素。如果链表为空返回null
peekLast();
对于list集合,底层判断元素是否相同,其实用的是元素自身的equals方法完成的。所以建议元素都要复写equals方法,建立元素对象自己的比较相同的条件依据。
练习:去除ArrayList中重复的元素
//去除ArrayList集合的重复元素。
import java.util.*;
class ArrayListTest
{
public static ArrayList singleElement(ArrayList a1)
{
ArrayList a2=new ArrayList();//创建集合a2
Iterator it=a1.iterator();//获取a1迭代器
while(it.hasNext())
{
//判断a2集合里是否已存在该元素,不存在则将元素存在a2集合里
Object obj=it.next();
if(!a2.contains(obj))
a2.add(obj);
}
return a2;
}
public static void main(String[] args)
{
ArrayList a1=new ArrayList();//创建集合a1
//添加元素
a1.add("java01");
a1.add("java02");
a1.add("java01");
a1.add("java02");
a1.add("java03");
System.out.println(a1);
a1=singleElement(a1);//调用函数
System.out.println(a1);
}
}
六、Set接口
概述:
Set接口的元素是无序的,存入和存出数据不一致。元素不可以重复。
Set接口中方法和Collection中方法是一致的Set接口取出方式只有一种迭代器。
|--HashSet:底层数据结构是哈希表,线程是不同步的,无序,高效。
HashSet集合保证元素唯一性:通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断equals是否为true
如果为true,那么视为相同元素不存。如果false,那么存储。
如果hashCode不同,那么不判断equals,从而提高对象比较的速度。
|--LinkedHashSet:有序,HashSet的子类
|--TreeSet:对Set集合中的元素进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在或者删除元素,底层依据的是hashCode方法和equals方法。
代码示例:往HashSet集合中存储Person对象。如果姓名和年龄相同,视为同一个人,视为相同元素。
import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
//复写hashCode()和equals()方法便于调用
public int hashCode()
{
return name.hashCode()+age*39;//一般要乘以一个数保证哈希值的唯一性
}
public boolean equals(Object obj)
{
if(!obj instanceof Person)
throw new RuntimeException("不是学生对象");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
public int getAge()
{
return age;
}
}
class
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("java01",11);
hs.add(new Person("java02",12);
hs.add(new Person("java03",13);
hs.add(new Person("java02",12);
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+p.getAge());
}
}
}
TreeSet:
用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性
如果元素不具备比较性,在运行时会发生ClassCastException异常
所以需要实现Comparable接口,强制让元素具备比较性,复写compareTo方法
TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复不存。
TreeSet集合排序方式有两种。Comparable和Comparator
1:让元素自身具备比较性,需要元素对象实现Comparable接口覆盖compareTo方法
2:让集合自身具备比较性,需要元素对象实现Comparator接口的比较器,并且覆盖compare方法并将该类对象作为实际参数传递给TreeSet集合的构造函数。
第二种方法比较灵活
第一种方式示例:
import java.util.*;
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",19));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();//强制转换回来
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class Student implements 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;
}
//复写compareTo方法
public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;//强制转换
//先按年龄排,再按名字排
System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)//主条件相同时判断次要条件
{
return this.name.compareTo(s.name);
}
return -1;
}
}
第二种方式示例:
import java.util.*;
class Student implements 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;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
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());
}
}
}
//定义一个类,实现Comparator接口,覆盖compare方法
class MyCompare implements Comparator//先比较名字再比较年龄
{
public int compare(Object o1,Object o2)
{
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;
}
}