Java: set和list集合类的使用方法

集合概述

由于Set集合和List集合都继承于Collection,都用于管理多个对象,所以统称为集合类。如下图所示:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

数组与集合类都可以用于管理多个对象,有何不同?

数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

集合类的特点?

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

Java集合框架实际上是java对各种数据结构的实现。比如,线性表,链表,队列,堆,栈,二叉树等,不像C语言,需要全部自己实现。

 

共性方法

由于大部分集合类都继承了Collection接口,所以Collection接口的方法就是集合类的共性方法,演示代码如下:

首先演示操作一个元素的方法,主要用于添加、删除和判断。一共6个:

public static void demo1(){  
    Collection col1=new ArrayList();  
    col1.add("java01");  
    col1.add("java02");  
    col1.add("java03");  
    col1.add("java04");  
    System.out.println(col1);  
    col1.remove("java01");  
    System.out.println(col1);  
    col1.clear();  
    System.out.println(col1.size());  
    System.out.println(col1.isEmpty());  
    System.out.println(col1.contains("java01"));  
    col1.add("java01");  
    System.out.println(col1.contains("java01"));  
}

运行结果:

[java01, java02, java03, java04]  
[java02, java03, java04]  
0  
true  
false  
true

由以上代码可知:

1.add方法的参数类型为Object

2.集合中存储的都是对象的引用

然后演示操作一组元素(集合)的方法,一共4个:

public static void demo2(){  
    Collection col1=new ArrayList();  
    col1.add("java01");  
    col1.add("java02");  
      
    Collection col2=new ArrayList();  
    col2.add("java01");  
    col2.add("java03");  
      
    String demoMethod="containsAll";  
    switch (demoMethod) {  
    case "addAll":  
        //求并集,重复不合并  
        col1.addAll(col2);//[java01, java02, java01, java03]  
        System.out.println(col1);  
        break;  
    case "removeAll":  
        col1.removeAll(col2);//[java02]求差集  
        System.out.println(col1);  
        break;  
    case "retainAll":  
        col1.retainAll(col2);//[java01]求交集  
        System.out.println(col1);  
        break;  
    case "containsAll":  
        col1.add("java03");  
        System.out.println(col1.containsAll(col2));//true  
    default:  
        break;  
    }         
}

学习本节后的结合框架如图,红色为本节学习:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

本节学了1个接口,10个方法的用法

迭代器

迭代器是逐个取出集合元素的方式,迭代器接口在各个集合类中实现都不一样。每个集合类的iterator()方法返回的迭代器对象也不一样,是每个集合内部定义的类。

使用迭代器获取元素的代码如下:

    public static void demo3(){  
        Collection col1=new ArrayList();  
        for (int i = 0; i < 10000; i++) {  
            col1.add("测试数据"+i);  
        }  
        long startTime=System.currentTimeMillis();  
        //用迭代器取出元素方式1,传统方式  
//      Iterator it=col1.iterator();  
//      while(it.hasNext()){  
//          System.out.println(it.next());  
//      }  
        //用迭代器取出元素方式2,将迭代器在for循环的第一个;前定义,可以提高性能  
        for (Iterator it=col1.iterator();it.hasNext();) {  
            System.out.println(it.next());  
        }  
        System.out.println(System.currentTimeMillis()-startTime);  
    }

学习本节后,集合框架体系图为:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

本节学习了1个接口,3个方法,本章到这学习了2个接口,13个方法

List集合共性方法

List接口和Set接口对比:

List:元素是有序的,元素可以重复。该集合体系有索引

Set:元素是无序的,元素不可以重复。

List集合特有方法。凡是可以操作角标的方法都是该体系特有的方法。元素索引从0开始。

add(index,element);加到index指向的元素前边

addAll(index,Collection);

remove(index);

set(index,element);

get(index);

indexOf();

subList(from,to);

listIterator();

public static void demo1(){  
        List list1=new ArrayList();  
        list1.add("java01");  
        list1.add("java02");  
        list1.add("java03");  
          
        List list2=new ArrayList();  
        list2.add("java04");  
        list2.add("java05");  
          
        String method="indexOf(element)";  
        switch (method) {  
        case "add(index,element)":  
            list1.add(0,"java04");  
            System.out.println(list1);  
            list1.add(1,"java05");  
            System.out.println(list1);  
            break;  
        case "addAll(index,Collection)":  
            list1.addAll(2,list2);  
            System.out.println(list1);  
            break;  
        case "remove(index)":  
            list1.remove(1);  
            System.out.println(list1);  
            list1.remove(1);  
            System.out.println(list1);  
            break;  
        case "set(index,element)":  
            list1.set(1, "java11");  
            System.out.println(list1);  
            break;  
        case "get(index)":  
            //获取一个元素  
            System.out.println(list1.get(0));  
            //获取所有元素  
            for (int i = 0,max=list1.size(); i < max; i++) {  
                System.out.println(list1.get(i));  
            }  
            break;  
        case "subList(from,to)":  
            List list3=list1.subList(1, 3);  
            System.out.println(list3);  
            break;  
        case "indexOf(element)":  
            int index=list1.indexOf("java01");  
            System.out.println(index);  
            break;  
        default:  
            break;  
        }  
    }

学习本节后集合框架体系图为:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

本节学习了1个接口,7个方法,本章到这学习了3个接口,20个方法

ListIterator

ListIterator是List集合特有的迭代器。ListIterator是Iterator的子接口。Iterator的局限性:Iterator迭代时不能通过集合对象的方法操作集合中的元素,否则会发生ConcurrentModificationException异常。所以在迭代时,只能用迭代器的方法操作元素,可是Iterator中只有判断,取出和删除的操作。如果想要进行其他操作如添加,修改等,就需要使用其他子接口,既ListIterator。该接口只能通过List集合的listIterator()方法获取。

下面的代码演示Iterator的局限性和remove方法

public static void demo2(){  
    List list1=new ArrayList();  
    list1.add("java01");  
    list1.add("java02");  
    list1.add("java03");  
      
    Iterator it=list1.iterator();  
    while(it.hasNext()){  
        Object obj= it.next();  
        if (obj.equals("java02")) {  
/               list1.add("java04");//不能添加元素,会报异常  
            it.remove();//Iterator的方法,从集合中删除java02的引用     
            System.out.println(obj);//删除的是引用而不是对象,所以能取到  
        }         
    }  
    System.out.println(list1);    
}

下面的代码演示ListIterator的用法

    public static void demo3(){  
        List list1=new ArrayList();  
        list1.add("java01");  
        list1.add("java02");  
        list1.add("java03");  
        System.out.println(list1);  
        ListIterator it=list1.listIterator();  
        while(it.hasNext()){  
            Object obj= it.next();  
            if (obj.equals("java02")) {  
                //可以用list迭代器自己的add和set方法,  
                //但不能同时使用,否则报异常  
//              it.add("java05");  
                it.set("java04");  
            }         
        }  
        System.out.println(list1);    
    }

下面的代码演示ListIterator正向遍历和逆向遍历

public static void demo4(){  
    List list1=new ArrayList();  
    list1.add("java01");  
    list1.add("java02");  
    list1.add("java03");  
              
    ListIterator it=list1.listIterator();  
  
    while(it.hasNext()){  
        System.out.println(it.nextIndex());  
        System.out.println(it.next());        
    }  
      
    while(it.hasPrevious()){  
        System.out.println(it.previousIndex());  
        System.out.println(it.previous());        
    }  
}

注意,直接逆向遍历是没有结果的,it.previousIndex()初始会返回-1。需要先用正向遍历把指针调到最后一个位置,才能开始逆向遍历,所以逆向遍历很少用,一般用previous()方法配合next()方法使用。

学习本节后集合框架体系图为:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

本节学习了1个接口,7个方法,本章到这学习了4个接口,27个方法

List集合具体对象特点

ArrayList:底层使用数组。特点:查询速度很快,增删稍慢,线程不同步。

LinkedList:底层使用链表。特点:增删很快,查询稍慢。

Vector:底层使用数组。线程同步。历史较长。现被ArrayList替代。

Vector中有一系列方法带element,这是它特有的方法,这些方法和Collection集合中的方法重复,且元素名过长,所以被取代,还有一个elements()方法返回Enumeration对象,Enumeration接口和Iterator接口功能雷同,但是方法名过长,所以被Iterator取代。

Vector中的部分方法演示如下:

public static void demo5(){  
    Vector v=new Vector();  
    v.add("java01");  
    v.add("java02");  
    v.add("java03");  
    v.add("java04");  
      
    Enumeration en=v.elements();  
    while (en.hasMoreElements()) {  
        System.out.println(en.nextElement());         
    }  
}

LinkedList

LInkedList特有方法:

添加元素

addFirst()

addLast()

获取元素,但删除元素。如果集合中没有元素,会出现NoSuchElementException

getFirst()

getLast()

获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException

removeFirst()

removeLast()

JDK1.6后出现了替代方法

添加元素

offerFirst()

offerLast()

获取元素,但删除元素。如果集合中没有元素,会返回null

peekFirst()

peekLast()

获取元素,但是元素被删除。如果集合中没有元素,会返回null

pollFirst()

pollLast()

演示代码如下:

public static void demo1(){  
    LinkedList  link=new LinkedList();  
    link.addFirst("java01");  
    link.addFirst("java02");  
    link.addFirst("java03");  
    link.addFirst("java04");  
    System.out.println(link);  
    String method="pollLast";  
    switch (method) {  
    case "addLast":  
        link.addLast("java05");  
        link.addLast("java06");  
        System.out.println(link);  
        break;  
    case "getFirst":  
        System.out.println(link.getFirst());  
        System.out.println(link);  
        break;  
    case "getLast":  
        System.out.println(link.getLast());  
        System.out.println(link);  
        break;  
    case "removeFirst":  
        System.out.println(link.removeFirst());  
        System.out.println(link);  
        break;  
    case "removeLast":  
        System.out.println(link.removeLast());  
        System.out.println(link);  
        break;  
    case "offerfirst":  
        link.offerFirst("java05");  
        link.offerFirst("java06");  
        System.out.println(link);  
        break;  
    case "offerLast":  
        link.offerLast("java05");  
        link.offerLast("java06");  
        System.out.println(link);  
        break;  
    case "peekFirst":  
        System.out.println(link.peekFirst());  
        System.out.println(link);  
        break;  
    case "peekLast":  
        System.out.println(link.peekLast());  
        System.out.println(link);  
        break;  
    case "pollFirst":  
        System.out.println(link.pollFirst());  
        System.out.println(link);  
        break;  
    case "pollLast":  
        System.out.println(link.pollLast());  
        System.out.println(link);  
        break;  
    default:  
        break;  
    }  
}

下面用LinkedList模拟一个堆栈或队列

堆栈:先进后出 First In Last Out FILO,如同一个杯子

队列:先进先出 First In First Out FIFO

import java.util.LinkedList;  
  
class Queue{  
    private LinkedList link;  
    public Queue(){  
        link=new LinkedList();  
    }  
    public void push(Object obj){  
        link.offerFirst(obj);  
    }  
    public Object pop(){  
        return link.pollLast();  
    }  
    public boolean isNull(){  
        return link.isEmpty();  
    }  
}  
class Stack{  
    private LinkedList link;  
    public Stack(){  
        link=new LinkedList();  
    }  
    public void push(Object obj){  
        link.offerFirst(obj);  
    }  
    public Object pop(){  
        return link.pollFirst();  
    }  
    public boolean isNull(){  
        return link.isEmpty();  
    }  
}  
  
  
public class LinkedListDemo {  
    public static void main(String[] args) {  
        Queue queue=new Queue();  
        queue.push("java01");  
        queue.push("java02");  
        queue.push("java03");  
        while (!queue.isNull()) {  
            System.out.println(queue.pop());          
        }  
          
        Stack stack=new Stack();  
        stack.push("java01");  
        stack.push("java02");  
        stack.push("java03");  
        while (!stack.isNull()) {  
            System.out.println(stack.pop());          
        }  
    }  
}

学习本节后集合框架体系图为:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

本节学习了1个类,12个方法,本章到这学习了1个类,4个接口,39个方法.

ArrayList

一般情况下创建集合默认用ArrayList,如果增删很多用LinkedList。编写代码去除ArrayList中的重复元素

import java.util.ArrayList;  
import java.util.Iterator;  
  
public class ArrayListDemo {  
    public static void main(String[] args) {  
        ArrayList list=new ArrayList();  
        list.add("java01");  
        list.add("java02");  
        list.add("java01");  
        list.add("java03");  
          
        list=singleElement(list);  
        System.out.println(list);  
    }  
    public static ArrayList singleElement(ArrayList list){  
        Iterator it=list.iterator();  
          
        ArrayList temp=new ArrayList();  
        while (it.hasNext()) {  
            Object object = (Object) it.next();  
            if (!temp.contains(object)) {  
                temp.add(object);  
            }  
        }     
        return temp;  
    }  
}

将自定义对象作为元素存到ArrayList集合中,并去除重复元素。

比如:存人独享。同姓名同年龄,视为同一个人,为重复元素。

import java.util.ArrayList;  
import java.util.Iterator;  
  
class Person{  
    private String name;  
    private int age;  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    public String getName() {  
        return name;  
    }  
    public int getAge() {  
        return age;  
    }  
    @Override  
    public boolean equals(Object obj) {  
        if (obj instanceof Person) {  
            Person p=(Person)obj;  
            return p.getName()==this.getName()&&p.getAge()==this.getAge();  
        }  
        return super.equals(obj);  
    }  
}  
  
  
public class ArrayListDemo {  
    public static void main(String[] args) {  
        ArrayList list=new ArrayList();  
        list.add(new Person("lisi01", 23));  
        list.add(new Person("lisi02", 21));  
        list.add(new Person("lisi03", 19));  
        list.add(new Person("lisi02", 21));  
          
        list=singleElement(list);  
        list.remove(new Person("lisi01", 23));  
          
        Iterator it=list.iterator();  
        while (it.hasNext()) {  
            Person p = (Person) it.next();  
            System.out.println(p.getName()+"的年龄为"+p.getAge());  
        }  
    }  
  
    public static ArrayList singleElement(ArrayList list){  
        Iterator it=list.iterator();  
          
        ArrayList temp=new ArrayList();  
        while (it.hasNext()) {  
            Object object = (Object) it.next();  
            if (!temp.contains(object)) {  
                temp.add(object);  
            }  
        }     
        return temp;  
    }  
}

上面的代码中实际上Person对象的equals方法是Collection对象的contains方法调用的。

本节学习了1个类(ArrayList),1个方法(equals()),截止到目前已经学习了3个类,4个接口,40个方法

HashSet

Set:元素是无序的(存入和取出的顺序不一致),元素不允许重复

|–HashSet:底层数据结构是哈希表。通过Object上的hashCode方法来判断元素是否重复,如果hashCode一样,则进一步通过equals方法判断,如果连equals都一样,则确认是重复元素

Set接口和Collection接口方法一样,所以用法没有区别。

hashCode()方法是Object类上的方法

下面的代码演示HashSet集合的元素无序性和唯一性

import java.util.HashSet;  
import java.util.Iterator;  
  
public class HashSetDemo {  
    public static void main(String[] args) {  
        HashSet set=new HashSet();  
        System.out.println(set.add("java01"));  
        System.out.println(set.add("java01"));  
        set.add("java02");  
        set.add("java03");  
        set.add("java04");  
          
        Iterator it=set.iterator();  
        while (it.hasNext()) {  
            System.out.println(it.next());        
        }  
    }  
}

在HashSet中存储自定义对象,例如Person对象,并重写hashCode和equals方法:

import java.util.HashSet;  
import java.util.Iterator;  
  
class Person{  
    private String name;  
    private int age;  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    public String getName() {  
        return name;  
    }  
    public int getAge() {  
        return age;  
    }  
    @Override  
    public boolean equals(Object obj) {  
        System.out.println(name+".equals");  
        if (obj instanceof Person) {  
            Person p=(Person)obj;  
            return p.getName()==this.getName()&&p.getAge()==this.getAge();  
        }  
        return super.equals(obj);  
    }  
    @Override  
    public int hashCode() {  
        System.out.println(name+".hashCode");  
        return name.hashCode()+age*39;  
    }  
}  
  
public class HashSetDemo {  
    public static void main(String[] args) {  
        HashSet set=new HashSet();  
        set.add(new Person("lisi01", 11));  
        set.add(new Person("lisi02", 21));  
        set.add(new Person("lisi02", 21));  
        set.add(new Person("lisi02", 26));  
        set.add(new Person("lisi03", 19));  
          
        Iterator it=set.iterator();  
        while (it.hasNext()) {  
            Person p=(Person)it.next();  
            System.out.println(p.getName()+"的年龄是"+p.getAge());        
        }  
    }  
}

下面演示HashCode的判断元素和删除元素方法

public static void main(String[] args) {  
    HashSet set=new HashSet();  
    set.add(new Person("a1", 12));  
    set.add(new Person("a2", 34));  
    set.add(new Person("a3", 56));  
      
    System.out.println(set.contains(new Person("a2", 34)));  
    System.out.println(set.remove(new Person("a2", 34)));  
      
    Iterator it=set.iterator();  
    while (it.hasNext()) {  
        Person p=(Person)it.next();  
        System.out.println(p.getName()+"的年龄是"+p.getAge());        
    }  
}

上面的代码和运行结果说明,HashSet的contains方法和remove方法也是靠hashCode()方法判断元素是否相同,hashCode相同再判断equals()方法。

本节学习了1个类(HashSet)、1个方法(hashCode())。本章到目前为止共学习了4个类、4个接口、41个方法

TreeSet

Set:无序,不可以重复元素。

|– HashSet:底层数据结构是哈希表。线程非同步的。

|– TresSet:可以对集合中的元素排序。底层数据结构是二叉树,通过元素的compareTo方法是否返回0保证元素唯一性。

TreeSet排序第一种方式:让元素自身具备比较性

元素需要实现Comparable接口,覆盖compareTo方法。

这种方式称为元素的自然顺序或默认顺序。

TreeSet排序第二种方式:让容器具备比较性。

创建TreeSet时传入实现Comparator接口的类,覆盖compare方法。

这种方式比较常用,且此方式比第一种方式优先级高。

下面的代码,演示一下TreeSet的顺序问题:

TreeSet ts=new TreeSet();  
ts.add("Dac");  
ts.add("aac");  
ts.add("bac");  
ts.add("bbc");  
  
Iterator it=ts.iterator();  
while(it.hasNext()){  
    System.out.println(it.next());  
}

运行结果:

Dac  
aac  
bac  
bbc

下面的代码演示TreeSet存储对象,并排序:

import java.util.Iterator;  
import java.util.TreeSet;  
  
class Student implements Comparable{  
    String name;  
    int age;  
    public Student(String name, int age) {  
        super();  
        this.name = name;  
        this.age = age;  
    }  
      
    public String getName() {  
        return name;  
    }  
    public int getAge() {  
        return age;  
    }  
  
    @Override  
    public int compareTo(Object o) {  
        if (!(o instanceof Student)) {  
            throw new RuntimeException();  
        }  
        Student s=(Student)o;  
        if (this.age>s.getAge()) {  
            return 1;  
        }else if (this.age==s.getAge()) {  
            return this.name.compareTo(s.name);  
        }  
        return -1;  
    }  
}  
  
public class TreeSetDemo {  
    public static void main(String[] args) {  
        demo2();  
    }  
    public static void demo2(){  
        TreeSet ts=new TreeSet();  
        ts.add(new Student("lisi01", 56));  
        ts.add(new Student("lisi02", 34));  
        ts.add(new Student("lisi03", 34));  
        ts.add(new Student("lisi04", 12));  
          
        Iterator it=ts.iterator();  
        while(it.hasNext()){  
            Student s=(Student)it.next();  
            System.out.println(s.getName()+"的年龄是:"+s.getAge());  
        }  
    }  
}

注意:存入TreeSet集合中的元素类必须实现Comparable接口,并覆盖compareTo方法。方法抛出异常。compareTo方法的作用是确定对象在集合中的顺序,如果compareTo方法返回1,则放在当前比较元素的后边,否则放前边。

下面的代码演示使用Comparetor来排序元素

import java.util.Comparator;  
import java.util.Iterator;  
import java.util.TreeSet;  
  
class Student implements Comparable{  
    String name;  
    int age;  
    public Student(String name, int age) {  
        super();  
        this.name = name;  
        this.age = age;  
    }  
      
    public String getName() {  
        return name;  
    }  
    public int getAge() {  
        return age;  
    }  
  
    @Override  
    public int compareTo(Object o) {  
        if (!(o instanceof Student)) {  
            throw new RuntimeException();  
        }  
        Student s=(Student)o;  
        if (this.age>s.getAge()) {  
            return 1;  
        }else if (this.age==s.getAge()) {  
            return this.name.compareTo(s.name);  
        }  
        return -1;  
    }  
}  
  
class MyComparator implements Comparator  
{  
  
    @Override  
    public int compare(Object o1, Object o2) {  
        Student s1=(Student)o1;  
        Student s2=(Student)o2;  
        int ret=s1.getName().compareTo(s2.getName());  
        if (ret==0) {  
            return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));  
        }  
        return ret;  
    }  
}  
  
public class TreeSetDemo {  
    public static void main(String[] args) {  
        demo2();  
    }  
    public static void demo2(){  
        TreeSet ts=new TreeSet(new MyComparator());  
        ts.add(new Student("lisi01", 56));  
        ts.add(new Student("lisi02", 34));  
        ts.add(new Student("lisi03", 34));  
        ts.add(new Student("lisi04", 12));  
          
        Iterator it=ts.iterator();  
        while(it.hasNext()){  
            Student s=(Student)it.next();  
            System.out.println(s.getName()+"的年龄是:"+s.getAge());  
        }  
    }  
}

下面的代码演示:在HashSet中存储字符串,并按字符串长度排序:

import java.util.Comparator;  
import java.util.Iterator;  
import java.util.TreeSet;  
  
public class TreeSetDemo2 {  
    public static void main(String[] args) {  
        TreeSet hs=new TreeSet(new Comparator() {  
  
            @Override  
            public int compare(Object o1, Object o2) {  
                String s1=(String)o1;  
                String s2=(String)o2;  
                int ret=new Integer(s1.length()).compareTo(new Integer(s2.length()));  
                if (ret==0) {  
                    return s1.compareTo(s2);  
                }  
                return ret;  
            }  
              
        });  
        hs.add("a");  
        hs.add("abd");  
        hs.add("abc");  
        hs.add("ab");  
        hs.add("abcd");  
          
        Iterator it=hs.iterator();  
        while(it.hasNext()){  
            System.out.println(it.next());  
        }     
    }  
}

本节共学习了2个接口(Comparable和Comparator),2个方法(compareTo和compare),1个类TreeSet,本章到这里共学习5个类,6个接口,43个方法。

下面是到本节结束为止学习的内容的UML类图:

Java: set和list集合类的使用方法
Java: set和list集合类的使用方法

转自:http://blog.csdn.net/Joven0/article/details/44890479

本文:Java: set和list集合类的使用方法

发表评论