Java集合
---------- android培训、java培训、期待与您交流!----------
1、集合的概念
集合就是一个储存对象的动态数组,由于Java是面向对象进行操作的,所以对对象的存是非常重要的,所以就产生了集合的概念。
数组虽然也可以储存对象,但是数组的长度是固定的,而集合长度是可以变化的,数组只能储存基本数据类型,集合可以储存任意类型对象。
Java中的集合类主要用于保存、盛装其它数据(集合里只能保存对象,实际上保存的是对象的引用变量),因此集合类也被称为容器类。Java的集合类主要由Collection和Map两个接口派生出,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类,所有的集合类都位于java.util包下。集合有很多种类,其继承关系如下图所示:
![](https://img-my.csdn.net/uploads/201406/24/1403573548_2644.jpg)
由于数据的存储方式即数据结构不同,所以其使用方法及功能各不相同,所以就产生了各种类型的容器类型。
2、Collection接口
Collection接口是Java集合框架的最大接口,但不能直接使用该接口,其主要子接口有:List、Set、Queue、SortedSet。
Collection提供了很多方法,如:
boolean add(Object o);用于向集合中添加元素
boolean addAll(Collection c);将集合c里的所有元素添加到指定的集合里
void clear();清除集合里的所有元素
bolean contains(Object o);返回集合里是否包含指定元素
boolean containsAll(Collection c);返回集合里是否含集合c里的所有元素
boolean isEmpty();返回集合是否为空。当集合长度为0时,返回true;否则返回false
Iterator iterator();返回一个Iterator对象,用于遍历集合里的元素
boolean remove(Object o);删除集合中指定元素
boolean removeAll(Collection c);从该集合中删除集合c里包含的元素
boolean retainAll(Collection c);从该集合中删除集合c里不包含的元素
int size();返回集合里元素的个数,即集合的长度
Object[] toArray();该方法把集合转换成一个数组,所有集合元素变成对应的数组
boolean addAll(Collection c);将集合c里的所有元素添加到指定的集合里
void clear();清除集合里的所有元素
bolean contains(Object o);返回集合里是否包含指定元素
boolean containsAll(Collection c);返回集合里是否含集合c里的所有元素
boolean isEmpty();返回集合是否为空。当集合长度为0时,返回true;否则返回false
Iterator iterator();返回一个Iterator对象,用于遍历集合里的元素
boolean remove(Object o);删除集合中指定元素
boolean removeAll(Collection c);从该集合中删除集合c里包含的元素
boolean retainAll(Collection c);从该集合中删除集合c里不包含的元素
int size();返回集合里元素的个数,即集合的长度
Object[] toArray();该方法把集合转换成一个数组,所有集合元素变成对应的数组
(1) Iterator接口
Java集合提供了一个标准的接口实现集合中元素的输出操作,主要有四种常见输出操作:
(1) Iterator (2) ListIterator (3) Enumeration (4) foreach
而以上四种输出以Iterator为操作的标准,该接口是最常使用的输出形式。
迭代器的输出原理为:将元素一个一个进行判断,判断其是否有内容,如果有则取出。
Iterator中常用的方法如下:
boolean hasNext();如果被迭代的集合元素还没有被遍历,则返回true
Object next();返回集合里下一个元素
void remove();删除集合里上一次next方法返回的元素。
Object next();返回集合里下一个元素
void remove();删除集合里上一次next方法返回的元素。
以下代码为Iterator输出的示例代码:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo {
public static void main(String[] args){
ArrayList a = new ArrayList();
a.add("abc");
a.add("def");
a.add("ghi");
for(Iterator it = a.iterator(); it.hasNext(); ){
System.out.println(it.next());
}
}
}
(2) List接口
List接口是Collection的子接口,其中可以保存重复的内容,其主要子类有ArrayList、LinkedList等。
与Collection不同的是,在List接口中扩充了Collection接口的一些主要方法,如:
boolean add(index, element);向指定的位置添加指定的元素
boolean addAll(index, Collection);向指定的位置开始,添加多个元素
boolean remove();移除元素(还有各种重载版本)
E set(index, element);将指定位置的元素修改为element
E get(index);由索引获取该位置上的元素
List subList(from, to);截取子List,从from开始到to结束,包含头,不含尾
ListIterator listIterator();List集合特有的迭代器
boolean addAll(index, Collection);向指定的位置开始,添加多个元素
boolean remove();移除元素(还有各种重载版本)
E set(index, element);将指定位置的元素修改为element
E get(index);由索引获取该位置上的元素
List subList(from, to);截取子List,从from开始到to结束,包含头,不含尾
ListIterator listIterator();List集合特有的迭代器
ListIterator是List集合特有的迭代器,是Iterator的子接口,在迭代时,不可以通过集合对象的方法操作
集合中的元素,因为会发生异常,所以在只能用迭代器的方法操作元素,如判断、取出、删除操作,若想进
行添加、修改等操作,就需要是用该ListIterator等子接口来实现,ListIterator的常用方法有:
void add(E e);将指定的元素插入列表(可选操作)
boolean hasNext();以正向遍历列表时,如果列表迭代器有多个元素,则返回 true
boolean hasPrevious();如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
E next();返回列表中的下一个元素
int nextIndex();返回对 next 的后续调用所返回元素的索引
E previous();返回列表中的前一个元素
int previousIndex();返回对 previous 的后续调用所返回元素的索引
void remove();从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)
void set(E e);用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)
boolean hasNext();以正向遍历列表时,如果列表迭代器有多个元素,则返回 true
boolean hasPrevious();如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
E next();返回列表中的下一个元素
int nextIndex();返回对 next 的后续调用所返回元素的索引
E previous();返回列表中的前一个元素
int previousIndex();返回对 previous 的后续调用所返回元素的索引
void remove();从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)
void set(E e);用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)
(a) ArrayList接口
ArrayList是List的子类,可以直接通过对象的多态性为List接口实例化,该类底层使用的数据结
构为数组,由于使用数组结构,具有角标,所以查询数据速度很快,增加及删减稍慢。
(b) LinkedList接口
LinkedList表示的是一个链表的操作类,增加及删减元素很快,查询很慢。
LinkedList的特有方法有:
void addFirst(E e);将指定元素插入此列表的开头
void addLast(E e);将指定元素添加到此列表的结尾
E getFirst();返回此列表的第一个元素。获取元素,不删除元素
E getLast();返回此列表的最后一个元素
E removeFirst();移除并返回此列表的第一个元素。获取元素,但是删除元素
E removeLast();移除并返回此列表的最后一个元素
E peekFirst();获取但不移除此列表的第一个元素;如果此列表为空,则返回 null
E peekLast();获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null
E pollFirst();获取并移除此列表的第一个元素;如果此列表为空,则返回 null
E pollLast();获取并移除此列表的最后一个元素;如果此列表为空,则返回 null
boolean offerFirst(E e);在此列表的开头插入指定的元素
boolean offerLast(E e);在此列表末尾插入指定的元素
void addLast(E e);将指定元素添加到此列表的结尾
E getFirst();返回此列表的第一个元素。获取元素,不删除元素
E getLast();返回此列表的最后一个元素
E removeFirst();移除并返回此列表的第一个元素。获取元素,但是删除元素
E removeLast();移除并返回此列表的最后一个元素
E peekFirst();获取但不移除此列表的第一个元素;如果此列表为空,则返回 null
E peekLast();获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null
E pollFirst();获取并移除此列表的第一个元素;如果此列表为空,则返回 null
E pollLast();获取并移除此列表的最后一个元素;如果此列表为空,则返回 null
boolean offerFirst(E e);在此列表的开头插入指定的元素
boolean offerLast(E e);在此列表末尾插入指定的元素
(c) Vetcor接口
在JDK1.0时即存在该类,其底层数据结构为数组,其增删改查都比较慢,被ArrayList等代替。
所以要根据实际需要选择合适的集合。
示例代码:
使用LinkedList模拟一个堆栈及队列结构
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
//使用Arraylist模拟一个堆栈或者队列结构
public class Queue {
public static void main(String[] args){
QueueDemo q = new QueueDemo();
q.myAdd("a");
q.myAdd("b");
q.myAdd("c");
q.myAdd("d");
while(!q.isNull()){
System.out.println(q.myGet());
}
}
}
class QueueDemo{
private LinkedList link;
QueueDemo(){
link = new LinkedList();
}
public void myAdd(Object obj){
link.addFirst(obj);
}
public Object myGet(){
return link.removeLast();//使用此行代码则为先进先出,即队列
// return link.removeFirst();//使用此行代码则为先进后出,即堆栈
}
public boolean isNull(){
return link.isEmpty();
}
}
(3) Set接口
Set接口也是Collection的子类,与List接口不同,Set接口不能加入重复的元素,其主要方法
与Collection基本一致。
Set的常用子类有HashSet与TreeSet。
(a) HashSet
HashSet是Set的一个子类,主要特点是:不能有重复的元素,数据采用散列存储的方式,底层数据
结构是hash表。
由于该类不能重复的存储元素,所以需要对需要存储的对象进行比较验证以保证对象的唯一性,
验
证主要依靠两个方法:
hashCode()与equals(),首先比较hash值区分是否为同一对象,若值不同
则认为
这两个对象是不同的,即可开辟空间存储对象。若比较hash值一样,则继续用equals方法比较是否是同
一个对象,若不是则存储,若相同,则只存储一个对象,这样就保证了对象的唯一性。
有时我们需要存储我们自定义的类的对象,所以按照默认的equals方法比较两个对象是否相同是不
够的,所以就需要自定义equals()方法覆写Object提供的默认比较方法来比较对象。
对于判断元素是否存在以及删除等操作也都是依赖于元素的hashcode()和equals()方法。
注意:在实际的开发中为了区分是否为同一对象问题,就需要在编写类时按照需求覆写hashcode()、
equals()以及toString()方法。
(b) TreeSet
TreeSet也是Set接口的子类,该类可以对集合中的元素进行指定顺序的排序,并且线程是不同步的。
TreeSet底层的数据结构为二叉树,用于对TreeSet集合进行元素的指定顺序排序,排序需要依据元素自身
具备的比较性,如果元素不具备比较性,在运行时会发生ClassCastException异常。所以需要元素实现
Comparable接口,强制让元素具备比较性,复写compareTo()方法。依据compareTo()方法的返回值,确
定元素在TreeSet数据结构中的位置。
TreeSet方法保证元素唯一性的方式:参考比较方法的结果是否为0,如果为0视为两个对 象重复。
TreeSet方法保证元素唯一性的方式:参考比较方法的结果是否为0,如果为0视为两个对 象重复。
注意:在进行比较时,如果判断元素不唯一,比如,同姓名,同年龄,才视为同一个人。
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。
TreeSet集合排序有两种方式,Comparable和Comparator区别:
(a) 让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法,示例如下:
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。
TreeSet集合排序有两种方式,Comparable和Comparator区别:
(a) 让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法,示例如下:
import java.util.Iterator;
import java.util.TreeSet;
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){
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;
}
}
public class TreeSetDemo {
public static void main(String[] args){
TreeSet t = new TreeSet();
t.add(new Student("AAAA",23));
t.add(new Student("AABB",13));
t.add(new Student("AACC",21));
for(Iterator it = t.iterator(); it.hasNext(); ){
Student s = (Student)it.next();
System.out.println(s.getName()+" "+s.getAge());
}
}
}
的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数,
示例如下:
修改(a)方法中的部分代码,并添加一个比较类。
public class TreeSetDemo {
public static void main(String[] args){
TreeSet t = new TreeSet(new MyCompare());
t.add(new Student("ADAA",23));
t.add(new Student("ABAB",13));
t.add(new Student("AGBB",13));
t.add(new Student("AACC",21));
t.add(new Student("BBDD",27));
for(Iterator it = t.iterator(); it.hasNext(); ){
Student s = (Student)it.next();
System.out.println(s.getName()+" "+s.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;
}
}
由以上示例代码可知,使用Comparator对两个对象进行比较更加实用,较为灵活。
3、Map接口
都使用key-value的形式储存在集合中。
特点:该集合存储键值对,一对一对往里存,而且要保证键的唯一性,不允许出现重复。
接口的常用子类有:HashTable、HashMap、TreeMap
(1) HashTable
该类是一个旧的子类,在JDK1.0时推出,采用同步处理方式,性能较低,且属于线程安全类型,不允许
将key设为null,现在使用较少。
(2) HashMap
在JDK1.2版本后推出,采用异步处理方式,其性能较高且属于非线程安全类,还允许将key设为null。
(3) TreeMap:底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。
Map接口的主要方法有:
(1) 添加。
put(K key, V value);将键值存储到集合,put方法的返回值,一般情况下是null,但是如果存储了重复的
键,替换原来老键的值,put方法的返回值就是被替换后的值
putAll(Map<? extends K,? extends V> m);存储一批键值
(2) 删除。
void clear();删除所有键值
V remove(Object key);根据键删除键值,若键存在,删除该键且返回值,若键不存在,返回null
(3) 判断。
boolean containsKey(Object key);判断该集合中是否有这个键
boolean containsValue(Object value);判断该集合中是否有这个值
boolean isEmpty();判断集中中是否有键值
(4) 获取。
V get(Object key);通过键获取值,若键存在,删除该键且返回值,若键不存在,返回null
int size();获取集合中键值对的数量
Collection<V> values();以集合的方式返回集合中包含的值
(5) 输出Map所有元素
由于Map接口中每个位置存放的时一对值,而Iterator每次只能找到一个值,所以Map接口不能向其它
单值集合一样可以直接用Iterator输出,需要使用以下两种Iterator方式输出。
(a) 使用keySet()方法
(a) 使用keySet()方法
将Map集合中所有的键存入到Set中,然后使用Set的迭代器以及Map的get()方法获取键值。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
class Person
{
private T name;
private R age;
Person(T name, R age){
this.name = name;
this.age = age;
}
public T getName(){
return name;
}
public R getAge(){
return age;
}
}
public class Map {
public static void main(String[] args) {
HashMap
m = new HashMap
();
m.put("AAA", 25);
m.put("AAB", 22);
m.put("BCA", 21);
m.put("DBA", 28);
Set
keyset = m.keySet();
for(Iterator
it = keyset.iterator(); it.hasNext(); ){ String key = it.next(); Integer value = m.get(key); System.out.println("key:"+key+" value:"+value); } } }
(b) 使用entrySet()方法及Map.Entry接口
Map.Entry是Map内部的一个接口,专门用来保存key-value的内容,它使static声明的内部接口(定义为内
部接口的原因是它保存的时key-value之间的映射关系,没有Map就没有映射关系),可以由外部调用,其中的
方法有:
public boolean equals(Object o);对象比较
public K getKey();取得key
public V getValue();取得value
public int hashCode();返回hash码
public boolean equals(Object o);对象比较
public K getKey();取得key
public V getValue();取得value
public int hashCode();返回hash码
public V setValue(V Value);设置value的值
示例代码:描述学生,将学生作为键,地址作为值保存在Map中,并获取Map中的每个元素
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
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;
}
public String toString(){
return name+" "+age;
}
public int hashCode(){ //覆写hashCode方法
return name.hashCode()+age*23;
}
public boolean equals(Object obj){ //覆写equals方法,判断两个对象是否是同一个
if(!(obj instanceof Student))
throw new RuntimeException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
@Override
//若该类需要存放到TreeMap等二叉树排序的集合中,就需要编写排序比较方法
public int compareTo(Student s) {
int num = new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
}
public class FanXing{
public static void main(String[] args){
Map
m = new HashMap
();
m.put(new Student("hao2", 27), "Hei");
m.put(new Student("hao1", 23), "Bei");
m.put(new Student("hao3", 28), "Tian");
m.put(new Student("hao1", 23), "Tian");
m.put(new Student("hao4", 21), "Shang");
Set
> set = m.entrySet(); for(Iterator
> it = set.iterator(); it.hasNext(); ){ Map.Entry
map = it.next(); Student student = map.getKey(); String addr = map.getValue(); System.out.println(student+" "+addr); } } }
---------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------