zoukankan      html  css  js  c++  java
  • 集合框架(List和Set)

    一、概述

    集合是一种可变数据项的容器,具有统一的父类接口Collection<E>Map并没有继承之),与其子集合的关系例如以下 图。集合的特点是长度可变,能够存储多种类型的对象(不加泛型时)。这也是与数组的两点最大的不同。

    这里写图片描写叙述
    java集合类关系图

    Collection最为根接口,ListSetQueue接口均直接继承自它,Map接口尽管不是直接继承自Collection,可是接口中使用到了Collection,即Map的数据也是使用Collection存储的。
    研究集合不可缺少的是先研究Collection接口的内容,先从接口名字定义開始说起public interface Collection<E> extends Iterable<E>,这是集合的根接口。<E>是JDK1.5開始的泛型,其功能是提高安全性,增强针对性,详细介绍后面再说。Iterable<E>接口是迭代器。以下有详细介绍。

    Collection接口提供了一些集合的共性方法,如:

    • boolean add(E e)加入一条数据。

    • boolean addAll(Collection<?

      extends E> c)加入还有一个集合内的元素。

    • void clear()清除全部数据。

    • boolean contains(Object o)是否包括指定数据。

    • Iterator<E> iterator()返回迭代器。
    • boolean remove(Object o)删除指定数据。
    • <T>T[] toArray(T[] a)返回数据的数组形式等等。
    • boolean retainAll(Collection<?> c)取与集合c的交集。
    • boolean removeAll(Collection<?> c)取与集合c的差集。

    二、迭代器

    一种集合的取出方式,用于集合的数据的遍历等。

    不同容器的数据结构不同,所以取出的动作实现不同,详细的取出动作定义在每一个容器的内部,这样取出方式就能够直接訪问集合内部元素。取出方式就被定义成了内部类。可是都有共性内容推断和取出,共性抽取便形成了Iterator接口(迭代器)。
    迭代器的使用演示样例(暂时不考虑泛型):

    ArrayList alist = new ArrayList();
    alist.add("java01");
    alist.add("java02");
    alist.add("java03");
    alist.add("java04");
    for(Iterator it = alist.iterator(); it.hasNext(); ) {
        System.out.println(it.next());
    }

    三、List

    List为Collection的常见子接口之中的一个,元素有序。能够反复,有索引。
    List有些特有的方法,和下标相关的一些方法。如:
    - 增:add(index, element)指定位置加入元素,addAll(index, Collection)指定位置加入一个集合的元素。


    - 删:remove(index)删除指定为的元素。
    - 改:set(index, element)改动指定位置的元素。
    - 查:get(index)获取指定位置的元素。subList(from, to)获取[from, to)段的子ListlistIterator()获取List特有的迭代器,indexOf(E)获取对象的位置。

    ListIterator

    ListIteratorIterator的子接口,在迭代时不能够通过集合的操作对集合进行操作,会发生并发改动异常,可是Iterator的操作是有限的,假设想对元素进行加入和改动等,就须要用到其子接口ListIterator,该接口仅仅能通过ListlistIterator()方法获取,演示样例代码例如以下:

    ArrayList alist = new ArrayList();
    alist.add("java01");
    alist.add("java02");
    alist.add("java03");
    alist.add("java04");
    for(ListIterator it = alist.listIterator(); it.hasNext(); ) {
        System.out.println(it.next());
        it.add("java");
    }
    System.out.println(alist);
    
    //输出结果是
    java01
    java02
    java03
    java04
    [java01, java, java02, java, java03, java, java04, java]

    通过上面能够看到,ListIterator在获取之后其遍历的内容就已经确定下来了。 ListIterator还有逆向遍历功能。

    ArrayList alist = new ArrayList();
    alist.add("java01");
    alist.add("java02");
    alist.add("java03");
    alist.add("java04");
    ListIterator it = alist.listIterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
    while(it.hasPrevious()) {
        System.out.println(it.previous());
    }
    // 输出的结果是
    java01
    java02
    java03
    java04
    java04
    java03
    java02
    java01

    List中详细对象特点

    List有三个详细的子类,各自是ArrayListLinkedListVector

    三者的特点与不同例如以下:

    • ArrayList:底层数据结构为数组结构,线程非同步。查询速度快,增删速度慢,效率比Vector高,最早出如今JDK1.2版本号。初始长度默觉得10。空间不足时50%延长。
    • LinkedList:底层数据结构为链表结构,线程非同步,查询速度慢,增删速度快,最早出如今JDK1.2版本号。

    • Vector:底层数据结构是数组结构,线程同步,与ArrayList有同样的功能。已被ArrayList取代,最早出如今JDK1.0版本号。

      默认长度为10,空间不足时100%延长。

    Vector的特点

    Vector的特有的一点就是,Vector的枚举(Vector的特有取出方式),和迭代器相似,名为EnumerationArrayList中没有此功能。可是由于方法名过长,且没有移除功能,已被Iterator取代,所以一般优先考虑使用Iterator。演示样例代码例如以下:

    Vector v = new Vector();
    v.add("java01");
    v.add("java02");
    v.add("java03");
    Enumeration en = v.elements();
    while(en.hasMoreElements()) {
        System.out.println(en.nextElement());
    }
    // 输出结果为
    java01
    java02
    java03

    LinkedList

    LinkedList的特有方法:addFirst(E e)addLast(E e)加入到头部或者尾部、getFirst()getLast()获取头部元素或者尾部元素、removeFirst()removeLast()删除头部元素或者尾部元素,并返回删除的元素,没有会报NoSuchElementException,这些是LinkedList所特有的方法。JDK1.6版本号名称发生了变化,分别变成了offerFirst(E e)offerLast(E e)peekFirst()peekLast()pollFirst()pollLast()。没有会返回null
    LinkedList练习,模拟队列进行加入和取出动作。演示样例代码例如以下:

    import java.util.*;
    class MyQueue {
        private LinkedList link;
        MyQueue() {
            link = new LinkedList();
        }
    
        public void myAdd(Object obj) {
            link.addFirst(obj);
        }
    
        public Object myGet() {
            return link.removeFirst();
        }
    
        public boolean isNull() {
            return link.isEmpty();
        }
    }
    
    class LinkedListTest {
        public static void main(String[] args) {
            MyQueue q = new MyQueue();
            q.myAdd("java01");
            q.myAdd("java02");
            q.myAdd("java03");
            q.myAdd("java04");
    
            while(!q.isNull()) {
                System.out.println(q.myGet());
            }
        }
    }

    ArrayList

    ArrayList练习,去除ArrayList中的反复项。

    代码示比例如以下:

    import java.util.*;
    class ArrayListTest {
    
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
    
            list.add("java01");
            list.add("java02");
            list.add("java01");
            list.add("java02");
            list.add("java01");
            list.add("java03");
    
            // 去除反复前
            System.out.println(list);
            list = singleElement(list);
            // 去除反复后
            System.out.println(list);
        }
    
        public static ArrayList singleElement(ArrayList list) {
            //定义一个暂时容器。
            ArrayList newList = new ArrayList();
            // 获取迭代器
            Iterator it = list.iterator();
            while(it.hasNext()) {
                Object obj = it.next();
                if(!newList.contains(obj)) {
                    newList.add(obj);
                }
            }
            return newList;
        }
    }

    ArrayList练习。自己定义类加入至ArrayList,须要覆盖自己定义类的equals方法。

    import java.util.*;
    class Person {
        private String name;
        private int age;
        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        // 覆盖equals方法
        public boolean equals(Object obj) {
    
            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;
        }
    
        public String toString() {
            return "Name:" + this.name + " Age:" + this.age;
        }
    }
    
    class ArrayListTest {
    
        public static void main(String[] args) {
            ArrayList list= new ArrayList();
            list.add(new Person("lisi01",30));
            list.add(new Person("lisi02",32));
            list.add(new Person("lisi02",32));
            list.add(new Person("lisi04",35));
            list.add(new Person("lisi03",33));
            list.add(new Person("lisi04",35));
    
            System.out.println(list);
            list = singleElement(list);
            System.out.println(list);
        }
    
        public static ArrayList singleElement(ArrayList al) {
            // 定义一个暂时容器。
            ArrayList newList = new ArrayList();
            // 取出迭代器
            Iterator it = al.iterator();
            while(it.hasNext()) {
                Object obj = it.next();
                if(!newList.contains(obj))
                    newList.add(obj);
            }
            return newList;
        }
    }

    四、Set

    元素无序(存入与取出的顺序不一致),元素不可反复。

    有两个主要子类:HashSetTreeSet

    • HashSet:底层数据结构为哈希表。

    • TreeSet:底层数据结构为二叉树。

    HashSet

    依据hashCode()equals()方法进行存储。add时。假设是第一次加入返回true(加入成功),否则返回false(加入失败)。演示样例代码例如以下:

    import java.util.*;
    class HashSetDemo { 
        public static void main(String[] args) {
            HashSet hs = new HashSet();
            // 第一次加入java01返回true
            System.out.println(hs.add("java01"));
            // 第二次加入java01返回false
            System.out.println(hs.add("java01"));
            hs.add("java02");
            hs.add("java03");
            hs.add("java03");
            hs.add("java04");
            // 遍历集合
            Iterator it = hs.iterator();
            while(it.hasNext()) {
                System.out.println(it.next());
            }
        }
    }

    HashSet存储自己定义对象,自己定义对象须要覆盖hashCodeequals方法。当hashCode值同样、equals返回真时,觉得是同一个对象。加入时。当hashCode值不同一时候,不会调用equals比較,当hashCode的值同样时,才会调用equals方法比較两个对象。

    演示样例代码例如以下:

    import java.util.*;
    /**
     *姓名和年龄同样觉得是同一个人
     */
    class Person {
        private String name;
        private int age;
        Person(String name,int age) {
            this.name = name;
            this.age = age;
        }
    
        public int hashCode() {
            System.out.println(this.name+"....hashCode");
            return name.hashCode() + age*37;
        }
    
        public boolean equals(Object obj) {
            if(!(obj instanceof Person))
                return false;
            Person p = (Person)obj;
            System.out.println(this.name+"...equals.."+p.name);
            return this.name.equals(p.name) && this.age == p.age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    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));
    
            // 遍历集合中的人
            Iterator it = hs.iterator();
            while(it.hasNext()) {
                Person p = (Person)it.next();
                System.out.println(p.getName()+"::"+p.getAge());
            }
        }
    }
    // 执行结果为
    a1....hashCode
    a2....hashCode
    a3....hashCode
    a2....hashCode
    a2...equals..a2
    a4....hashCode
    a3::13
    a1::11
    a4::14
    a2::12

    从上面代码执行的结果能够看出,当加入new Person("a2",12)时。由于集合中已经有这个人了。所以hashCode的返回值已经存在。因此便会调用equals方法推断,终于结果还是此人已存在,所以最总集合中仅仅有4个人。
    HashSet的推断和删除依据,能够看到判读元素是否存在和删除元素都是首先依据hashCode值,然后再通过equals推断是否同样。

    import java.util.*;
    /**
     *姓名和年龄同样觉得是同一个人
     */
    class Person {
        private String name;
        private int age;
        Person(String name,int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         *统一返回1作为哈希值
         */
        public int hashCode() {
            System.out.println("hashCode");
            return 1;
        }
    
        /**
         * 姓名和年龄同样觉得是同一个人
         */
        public boolean equals(Object obj) {
            if(!(obj instanceof Person))
                return false;
            Person p = (Person)obj;
            System.out.println(this.name+"...equals.."+p.name);
            return this.name.equals(p.name) && this.age == p.age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    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("--------");
    
            // 推断是否存在元素
            hs.contains(new Person("a4", 14));
            System.out.println("--------");
    
            // 删除指定元素
            hs.remove(new Person("a1", 11));
        }
    }
    // 执行结果为
    hashCode
    hashCode
    a2...equals..a1
    hashCode
    a3...equals..a1
    a3...equals..a2
    hashCode
    a2...equals..a1
    a2...equals..a2
    hashCode
    a4...equals..a1
    a4...equals..a2
    a4...equals..a3
    --------
    hashCode
    a4...equals..a1
    a4...equals..a2
    a4...equals..a3
    a4...equals..a4
    --------
    hashCode
    a1...equals..a1

    TreeSet

    能够对集合中的元素进行排序。

    底层数据结构为二叉树。中序遍历便是TreeSet的顺序。

    演示样例代码例如以下:

    import java.util.*;
    class TreeSetDemo {
        public static void main(String[] args) {
            TreeSet ts = new TreeSet();
            ts.add("asdas");
            ts.add("abc");
            ts.add("beds");
            ts.add("abd");
            Iterator it = ts.iterator();
            while(it.hasNext()) {
                System.out.println(it.next());
            }
        }
    }
    // 执行结果为
    abc
    abd
    asdas
    beds

    对于自己定义对象的排序,一般有两种做法,一是自己定义对象自己实现Comparable接口。二是集合提供比較器(Comparator接口)。


    自己定义对象实现Comparable接口,演示样例代码例如以下:

    import java.util.*;
    
    class Student implements Comparable {
        private String name;
        private int age;
    
        Student(String name,int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         *比較结果又三种。负数表示小于,0表示等于,正数表示大于
         */
        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) {
                // String类已经实现了Comparable接口
                return this.name.compareTo(s.name);
            }
            return -1;
        }
    
        public String getName() {
            return name;
    
        }
    
        public int getAge() {
            return age;
        }
    }
    
    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());
            }
        }
    }

    集合提供比較器(Comparator接口)的比較方式。用于元素不具备比較性或者具备的比較性不是用户所须要的时。演示样例代码例如以下:

    import java.util.*;
    class Student implements Comparable {
        private String name;
        private int age;
    
        Student(String name,int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         *比較结果又三种,负数表示小于,0表示等于,正数表示大于
         */
        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;
        }
    
        public String getName() {
            return name;
    
        }
    
        public int getAge() {
            return age;
        }
    }
    
    class TreeSetDemo2 {
        public static void main(String[] args) {
            TreeSet ts = new TreeSet(new MyCompare());
    
            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));
            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 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;
        }
    }

    五、泛型

    泛型的出现攻克了类型不同的安全问题,JDK1.5版本号開始出现的。详细做法就是在集合定义时指明数据类型。如ArrayList<String> list= new ArrayList<String>(),这样一来假设向list中加入非String类型对象时。就会在编译时期提示ClassCastException异常。演示样例代码例如以下:

    import java.util.*;
    class GenericDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("abc01");
            list.add("abc0991");
            list.add("abc014");
    
            // Iterator也有相应的泛型
            Iterator<String> it = al.iterator();
            while(it.hasNext()) {
                System.out.println(s+":"+s.length());
            }
        }
    }

    自己定义类中使用泛型的概念。试用于用数据类型不确定时,演示样例代码例如以下:

    class Worker {
    
    }
    class Student {
    
    }
    
    /**
     *泛型类,使用与引用数据类型不确定时。
     */
    class Utils<Q> {
        private Q q;
        public void setObject(Q q) {
            this.q = q;
        }
    
        public Q getObject() {
            return q;
        }
    }
    class  GenericDemo3 {
        public static void main(String[] args) {
            Utils<Worker> u = new Utils<Worker>();
            u.setObject(new Worker());
            Worker w = u.getObject();;
        }
    }

    泛型定义在方法上,演示样例代码例如以下:

    class Demo {
        public <T> void show(T t) {
            System.out.println("show:"+t);
        }
    
        public <Q> void print(Q q) {
            System.out.println("print:"+q);
        }
    
        /**
         * 静态方法不能够訪问类上的泛型。可使用静态泛型方法。注意:泛型标识<E>需放在返回值前。

    */ public static <E> void printf(E e) { System.out.println("printf:"+e); } } class GenericDemo4 { public static void main(String[] args) { Demo demo = new Demo(); demo.show("Hi"); demo.print("Hello"); Demo.printf(5); } } //执行结果为 show:Hi print:Hello show:5

    泛型限定

    一般有三种情况。

    • <?

      >:?为通配符。

    • <? extends E>:E和E的子类。称为上限。

    • <? super E>:E和E的父类。称为下限。

    如对全部类型的ArrayList进行遍历输出,演示样例代码例如以下:

    public static void print(ArrayList<?> list) {
        Iterator<?> it = list.iterator();
        while(it.hasNext()) {
            System.out.println(it.next().toString());
        }
    }

    Person或者Person的子类Student进行遍历并输出,演示样例代码例如以下:

    public static void print(ArrayList<? extends Person> list) {
        Iterator<? extends Person> it = list.iterator();
        while(it.hasNext()) {
            System.out.println(it.next().getName());
        }
    }

    对于<?

    super E>并不经常使用。举一个TreeSet里的样例,TreeSet(Comparator<?

    super E> comparator),使用父类的比較器进行子类的比較。演示样例代码例如以下:

    import java.util.*;
    class Person {
        private String name;
        Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public String toString() {
            return "Person :"+name;
        }
    }
    
    class Student extends Person {
        Student(String name) {
            super(name);
        }
    }
    
    class Worker extends Person {
        Worker(String name) {
            super(name);
        }
    }
    
    /**
     * 定义使用与Person的比較器
     */
    class Comp implements Comparator<Person> {
        public int compare(Person p1,Person p2) {
            // 倒序
            return p2.getName().compareTo(p1.getName());
        }
    }
    
    class GenericDemo {
        public static void main(String[] args) {
    
            // 使用使用父类的比較器进行比較
            TreeSet<Student> ts = new TreeSet<Student>(new Comp());
            ts.add(new Student("abc03"));
            ts.add(new Student("abc02"));
            ts.add(new Student("abc06"));
            ts.add(new Student("abc01"));
            Iterator<Student> it = ts.iterator();
            while(it.hasNext()) {
                System.out.println(it.next().getName());
            }
    
            // 使用使用父类的比較器进行比較
            TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp());
            ts1.add(new Worker("wabc--03"));
            ts1.add(new Worker("wabc--02"));
            ts1.add(new Worker("wabc--06"));
            ts1.add(new Worker("wabc--01"));
            Iterator<Worker> it1 = ts1.iterator();
            while(it1.hasNext()) {
                System.out.println(it1.next().getName());
            }
        }
    }
    // 执行结果为
    abc06
    abc03
    abc02
    abc01
    wabc--06
    wabc--03
    wabc--02
    wabc--01
  • 相关阅读:
    Delphi/XE2 使用TIdHttp控件下载Https协议服务器文件[转]
    [Delphi]实现使用TIdHttp控件向https地址Post请求[转]
    让PowerShell用上Git
    解答WPF中ComboBox SelectedItem Binding不上的Bug
    那么小伙伴么,问题来了,WPF中,控件的Width="*"在后台怎么写?
    WPF Adorner+附加属性 实现控件友好提示
    关于Mvvm的一些深入理解
    第一个WP8程序,照相机
    夜深了,我们为什么加班(转载)
    Linux学习-SRPM 的使用 : rpmbuild (Optional)
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8450301.html
Copyright © 2011-2022 走看看