Java集合简述(一)
集合(Collection接口):用以存储对象;长度可变;课存放多种类型
集合存放的是对象地址(引用)
常见子接口:List Set
下面先讲以一些Collection接口中定义的关于集合共有的方法:
1,添加
add(Object obj); 向集合添加对象
addAll(collection);向集合添加一组对象
2,删除
remove(Object obj); 删除指定对象
removeAll(collection c); 删除c中存在的对象
clear(); 清空集合
3,判断。
contains(Object obj); 判断集合中是否存在指定对象
isEmpty(); 判断是否为空
4,获取
iterator(); 返回集合上的迭代器(Iterator)
Iterator提供的方法有:
hasNext():判断下面是否还有元素,如果有返回true,否则返回false
next():获取迭代器中的下一个元素
remove():删除当前元素(集合中的元素同时被删除)
size(); 获取集合内对象个数
5,获取交集。
retainAll(collection c); 只保留与c集合中相同的对象
6,集合变数组。
toArray();
1.集合的子接口 List
List中的元素有序,可以重复,以索引访问元素。下面介绍一下List特有的方法:
增:
add(int index,E e):指定位置添加元素
addAll(int index,Collection c):指定位置添加一组元素
删:
remove(int index):删除指定索引处的元素
改:
set(int index,E e):修改指定位置的元素
查:
get(int index):通过索引获取元素
indexOf(Object o):获取对象第一次出现位置的索引
lastindexOf(Object o):获取对象最后一次出现位置的索引
subList(int first , int end):获取集合中索引从first到end的元素
(不包含索引为end的元素)
listIterator():获取ListIterator迭代对象
List集合特有的迭代器。ListIterator是Iterator的子接口。
注意:在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的方法操作元素,
可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。
ListIterator的方法:(ListIterator的所有方法均在当前访问的位置操作)
add(E e):添加元素
set(E e):修改元素
hasPrevious():判断前面有没有元素,用于逆向遍历
previous():返回前一个元素
注意:在List中的contains(Objectobj):判断集合中是否存在指定对象
和remove()函数,底层都是调用equals()函数
1.1 实现List接口的具体类:ArryList
ArryList底层使用数组数据结构。特点:查询速度很快;但是增删稍慢。线程不同步。
ArryList没有特殊的函数用法,下面用一个例子来具体看一下ArryList的用法:
class ArryListDemo
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
//添加元素。
al.add("java01"); //add(Object obj);
al.add("java02");
al.add("java03");
al.add("java04");
for(Iterator it = al.iterator(); it.hasNext() ; ) //获取迭代器,用于取出集合中的元素。
{
System.out.println(it.next());
}
//打印原集合。
System.out.println("原集合:"+al);
//删除元素。
al.remove("java02");
//判断元素。
System.out.println("java03是否存在:"+al.contains("java03"));
System.out.println("集合是否为空?"+al.isEmpty());
//获取个数。集合长度。
System.out.println("size:"+al.size());
//打印改变后的集合。
System.out.println(al);
al.clear();//清空集合。
}
1.2 实现List接口的具体类:LinkedList
LinkedList底层使用链表数据结构。特点:增删速度很快;查询稍慢。线程不同步
LinkedList有自己的一些特殊函数,介绍如下:
addFirst():在开头位置添加元素
addLast():在末尾添加元素
removeFirst():删除并返回第一个元素 (列表为空时抛出异常)
removeLast():删除并返回最后一个元素
getFirst():获取第一个元素
getLast():获取最后一个元素
在JDK1.6出现了上述方法的替代方法,如下:
offerFirst(); 添加元素
offerLast();
pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。
2.集合的子接口Set
元素无序,不可以重复,无索引。具有的方法和Collection一样。下面主要介绍它的两个子类:
2.1 实现Set接口的具体类 HashSet
HashSet底层数据结构为哈希表
因为Set集合中的元素不允许重复,所以在存储的时候,HashSet必须要保证元素的唯一性。
HashSet通过元素的两个方法,hashCode()和equals()来保证元素的唯一性。
用HashSet存储自定义对象时,一般会在自定义的对象类里重写hashCode()和equals()函数。
hashCode()返回对象的哈希值,也就是地址值,存储时首先调用hashCode()函数
如果元素的HashCode值相同,才会判断equals()是否为true。
如果元素的hashCode值不同,不会调用equals()。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法都是元素的hashCode和equals方法。
下面通过例子再来看一下:定义一个描述人的类,通过hashSet集合存储。姓名和年龄相同为同一个人,重复元素。
class HashSetTest
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a2",12));
hs.add(new Person("a4",14));
System.out.println("a1:"+hs.contains(new Person("a2",12))); //判断hs中是否存在new Person("a2",12)
hs.remove(new Person("a4",13)); //删除new Person("a4",13)
Iterator it = hs.iterator(); //获取迭代对象
while(it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()
{
return name.hashCode()+age*37; //重写hashCode函数,尽量使不同的对象返回不同的哈希值
}
public boolean equals(Object obj) //重写equals函数,根据需求重写判定条件
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
2.2 实现Set接口的具体类 TreeSet
TreeSet底层数据结构为二叉树可以自动对Set集合中的元素进行排序
存储自定义对象时必须实现Compareable接口,
覆写int compareTo(Object o)方法,指定比较方式, 使对象具有比较性。
返回1:this > o
返回0:this = o 保证元素唯一性的依据:compareTo方法return 0。
返回-1:this < o
TreeSet通过compareTo函数的返回值来对集合中的元素进行排序。
当compareTo()方法返回0时,系统默认两个对象为同一对象,所以当对象有多个属性时,必须比较多次
即排序时,当主要条件相同时,一定判断一下次要条件。如下所示: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));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi01",40));
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 int compareTo(Object obj) //根据需求,重写compareTo方法,告诉TreeSet排序依据
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
if(this.age>s.age) //首先按年龄排序
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name); //当年龄相同是再按姓名比较
}
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
TreeSet还有第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式:创建TreeSet对象时,传入一个比较器:
比较器:定义一个类,实现Comparator接口,覆盖compare方法。
class Student
{
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",20));
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)
{
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;
}
}
当两种排序都存在时,以比较器为主。而且在写程序的时候多使用比较器方式。