java-集合框架

一 集合的由来

需求1:20个学员。用Student描述,创建Student对象。
既然对象很多先进行存储---数组。

Student[] stus = new Student[20];

需求2:又来来了一个新学员。
原来的容器用不了。数组的长度是固定的。

解决:
创建一个新数组,将原来数组中的元素复制到新数组中。
麻烦。Java中提供解决问题的对象---->集合。

当数据多了需要存储,需要容器,而数据的个数不确定,无法使用数组,这时可以使用Java中另一个容器--集合。

集合和数组的区别?
数组的长度是固定的。
集合的长度是可变的。

数组中存储的是同一类型的元素,可以存储基本数据类型值。
集合存储的都是对象。而且对象的类型可以不一致。

什么时候使用集合呢?
当对象多的时候,先进行存储。

这些容器怎么区分?

区分的方式:每一个容器的数据结构不一样。
数据存储到的一种方式。

不断的向上抽取过程中,出现体现,形成了集合框架。
最顶层:Collection接口。
学习体系:看顶层,用底层。

了解顶层Collection:
一个容器:添加,删除,获取等功能。

Collection:
|--List:有序的,带索引的,通过索引就可以精确的操作集合中的元素,元素是可以重复的。
List提供了增删改查动作
增加add(element) add(index,element) ;
删除remove(element) remove(index);
修改set(index,element);
查询get(index);
|--Set:

//    演示Collection中带all方法 
    public static void collectionDemo2(Collection c1,Collection c2){
        
        //1,给两个集合添加元素。
        c1.add("abc1");
        c1.add("abc2");
        c1.add("abc3");
        
        c2.add("abc1");
        c2.add("abc4");
        c2.add("abc5");
        
        //添加所有c2的元素到c1中。
//        c1.addAll(c2);
        
//        boolean b = c1.containsAll(c2);
//        System.out.println("b="+b);
        
        //删除c1中所有和c2相同的元素。
//        c1.removeAll(c2);
        
        //保留了c1中和c2相同的元素。
        c1.retainAll(c2);
        
        //打印。
        System.out.println("c1="+c1);
        
    }
    
//    演示Collection中常见的一般方法。
    public static void collectionDemo(Collection coll) {
        
        //1,往集合中添加对象元素。add(Object);
        coll.add("itcast1");
        coll.add("itcast2");
        coll.add("itcast3");
        
        
        //2,删除。
//        coll.remove("itcast2");
        
        //3,判断是否包含。
        System.out.println(coll.contains("itcast11"));
        
        //4,清除。
        coll.clear();
        //把集合打印一下。
        System.out.println(coll);//[itcast1, itcast2, itcast3]
        
    }

1.1 集合框架图

 图1

 

 

 

 

1.2 集合的细节@

public static void main(String[] args) {
        
        Collection coll = new ArrayList();
        
        /*
         * 细节。
         * 1,集合中存储其实都是对象的地址。
         * 2,集合中可以存储基本数值吗?不行,但是jdk1.5以后可以这么写,但是存储的还是对象(基本数据类型包装类对象)。
         * 3,存储时提升了Object。取出时要使用元素的特有内容,必须向下转型。
         */
        
        //coll存储元素。
//        coll.add("abc1");//存储的是对象的引用//        coll.add(3);//coll.add(Integer.valueOf(3));//自动装箱。
        

        coll.add("itcast1");//Object obj = "itcast1";提升为了Object
        coll.add("hehe");//
        coll.add("nba");
        
        for (Iterator it = coll.iterator(); it.hasNext();) {
            
            Object object = it.next();//取出来的都是Object。需要使用元素的特有方法时需要向下转型。
            String str = (String)object;
            System.out.println(str.length());
            
        }
    }

1.3  重复的概念equals

里面的重复是指的是引用是否重复,也就是equals方法来比较的,你也可以重写equals 方法。建立自己的比较方式

 重复都是有判断依据的,都是通过方法来完成的。

public boolean equals(Object obj) {
        if(this == obj)
            return true;
        if(! (obj instanceof Student))
            throw new RuntimeException("类型异常");
        Student stu = (Student)obj;
        
        return (this.name.equals(stu.name) && (this.age == stu.age));
    }

    public static void main(String[] args) {
        Collection coll = new ArrayList();
        
        Student stu = new Student(21,"lishi");
        coll.add(stu);
        coll.add(new Student(21,"lisi"));
        for (Iterator iterator = coll.iterator(); iterator.hasNext();) {
            Student  student = (Student) iterator.next();
            System.out.println(student.toString());
            
        }

 

二 迭代@

也是集合的取出方式

public static void main(String[] args) {
        /*
         * 集合的取出方式。
         * 
         * 迭代器是Collection集合中通用的取出方式。
         * 
         */
        //1,创建集合对象。
        Collection coll = new ArrayList();
        coll.add("abc1");
        coll.add("abc2");
        coll.add("abc3");
        coll.add("abc4");
        
        /*//2.获取容器的迭代器对象。通过iterator方法。
        Iterator it = coll.iterator();
        
        //3,使用具体的迭代器对象获取集合中的元素。参阅迭代器的方法
        while(it.hasNext()){
            System.out.println(it.next());
        }*/
        
        for (Iterator it = coll.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }
        
        
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());
//        System.out.println(it.next());//java.util.NoSuchElementException没有这个元素异常。
    }

}

三 ListIterator 

package cn.itcast.api.a.ListIterator;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        
        List list = new ArrayList();
        
        list.add("itcast1");
        list.add("itcast2");
        list.add("itcast3");
        list.add("itcast4");
        
        /*
         *  获取集合中的元素。
         *  如果集合中有元素等于 itcast2.那么就插入一个新的元素,java。
         *  
         *  引发了java.util.ConcurrentModificationException
         *  在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。
         *  
         *  解决:在迭代时,不要使用集合的方法操作元素。
         *  那么想要在迭代时对元素操作咋办?可以使用迭代器的方法操作。
         *  可是很遗憾:迭代器的方式只有 hasNext() ,next(),remove();
         *  Iterator有一个子接口ListIterator可以完成该问题的解决。如何获取该子接口对象呢?
         *  通过List接口中的listIterator()就可以获取,
         *  记住:该列表迭代器只有List接口有。而且这个迭代器可以完成在迭代过程中的增删改查动作。
         *  
         *  
         */
//        Iterator it = list.iterator();
//        获取列表迭代其对象
        ListIterator it = list.listIterator();
        
        while(it.hasNext()){
            
            Object obj = it.next();
            if("itcast2".equals(obj)){
//                list.add("java");
//                it.add("java");
                it.set("java");
            }
        }
        
        System.out.println(list);

    }

}

四 List

|--List:有序的,带索引的,通过索引就可以精确的操作集合中的元素,元素是可以重复的。
List提供了增删改查动作
增加add(element) add(index,element) ;
删除remove(element) remove(index);
修改set(index,element);
查询get(index);

|--Vector:可以增长的数组结构。同步的。效率非常低。已被ArrayList替代。
|--ArrayList:是数组结构,长度是可变的(原理是创建新数组+复制数组),查询速度很快,增删较慢,不同步的。
|--LinkedList:是链表结构,不同步的,增删速度很快,查询速度较慢。
可用于实现堆栈,队列。
堆栈:先进后出 First in Last Out FILO 手枪弹夹。
队列:先进先出 First in First Out FIFO 排队买票。
List可以存储重复元素的,如果需求中要求容器中的元素必须保证唯一性。

 

4.1 LinkedList

package cn.itcast.api.b.list.subclass;

import java.util.LinkedList;

public class LinkedListDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        /*
         * LinkedList做个了解。
         * 特有:围绕头和尾展开定义的。First Last。
         * addFirst();
         * addLast();
         * 
         * getFirst();:获取头部元素。
         * getLast();
         * 
         * removeFirst();获取头部元素,并删除头部元素。
         * removeLast();
         */
        
        LinkedList link = new LinkedList();
        
        link.addFirst("abc1");
        link.addFirst("abc2");
        link.addFirst("abc3");
        
//        System.out.println(link.getFirst());
//        System.out.println(link.getFirst());
        
//        System.out.println(link.removeFirst());
//        System.out.println(link.removeFirst());
//        System.out.println(link.removeFirst());
//        System.out.println(link.removeFirst());
        
        while(!link.isEmpty()){
            
            System.out.println(link.removeLast());
        }
        
        
    }

}

 

4.1.1 用LinkList模拟栈和队列

package cn.itcast.api.b.list.subclass;

import java.util.LinkedList;

public class LinkedListTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*
         * 面试题:用LinkedList模拟一个堆栈或者队列数据结构。
         * 创建一个堆栈或者队列数据结构对象,该对象中使用LinkedList来完成的。
         * 
         * 自定义堆栈结构。作业。
         */
        //创建一个队列对象。
        Queue queue = new Queue();
        //往队列中添加元素。
        queue.myAdd("itcast1");
        queue.myAdd("itcast2");
        queue.myAdd("itcast3");
        queue.myAdd("itcast4");
        
        while(!queue.isNull()){
            System.out.println(queue.myGet());
        }
    }
}
/**
 * 定义一个队列数据结构。Queue
 */
class Queue{
    //封装了一个链表数据结构。
    private LinkedList link;
    /*
     * 队列初始化时,对链表对象初始化。
     */
    Queue(){
        link = new LinkedList();
    }
    
    /**
     * 队列的添加元素功能。
     */
    public void myAdd(Object obj){
        //内部使用的就是链表的方法。
        link.addFirst(obj);
    }
    
    /**
     * 队列的获取方法。
     */
    public Object myGet(){
        return link.removeLast();
    }
    
    /**
     * 判断队列中元素是否空,没有元素就为true。
     */
    public boolean isNull(){
        return link.isEmpty();
    }
}

 

4.1.2 去重复元素

4.2 equals

package cn.itcast.api.b.list.subclass;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import cn.itcast.domain.Student;
public class ArrayListTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        List list = new ArrayList();
//        list.add("abc1");
//        list.add("abc2");
//        list.add("abc1");
//        list.add("abc2");
//        list.add("abc1");
//        list.add("abc2");
        
        list.add(new Student("lisi1",21));
        list.add(new Student("lisi2",22));
        list.add(new Student("lisi1",21));
        list.add(new Student("lisi2",22));
        list.add(new Student("lisi1",21));
        
        getSingleElement(list);//去除重复元素。
        
        System.out.println(list);

    }
    
    /*
     * 案例:去除List集合中的重复元素。
     * 
     * 思路:
     * 1,先创建一个临时容器。用于存储唯一性的元素。
     * 2,遍历原容器,将遍历到的元素到临时容器中去判断,是否存在。
     * 3,如果存在,不存储到临时容器,如果不存在,存储到临时容器中。
     * 4,遍历结束后,临时容器中存储的就是唯一性的元素。
     * 5,如果需要将这些唯一性的元素保留到原容器中,只要将原容器清空,将临时容器中的元素添加到原容器中即可。
     * 
     */
    public static void getSingleElement(List list){
        
        //1,创建一个临时容器。
        List temp = new ArrayList();
        
        //2,遍历原容器。
        for (Iterator it = list.iterator(); it.hasNext();) {
            Object obj = it.next();
            
            //对遍历到的每一个元素都到临时容器中去判断是否包含。
            if(!temp.contains(obj)){//如果不存在,
                temp.add(obj);//添加到临时容器。
            }
        }
        //唯一性的元素已经被记录到临时容器中。
        //清空原容器中的元素。
        list.clear();
        
        //把临时容器中的元素添加到原容器中。
        list.addAll(temp);
        
    }

}



/**
* 重写了equals方法,建立Student对象判断相同的依据。
*/
@Override
public boolean equals(Object obj) {


System.out.println("equals");
if (this == obj)
return true;


if (!(obj instanceof Student)) {
throw new ClassCastException();
}


Student stu = (Student) obj;
return this.name.equals(stu.name) && this.age == stu.age;
}

 

 

 五 set

|--Set:不包含重复元素的集合,不保证顺序。而且方法和Collection一致。Set集合取出元素的方式只有一种:迭代器。
  |--HashSet:哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode(),equals()方法。查询速度快。
  |--TreeSet:可以对Set集合中的元素进行排序。使用的是二叉树结构。如何保证元素唯一性的呢?
使用的对象比较方法的结果是否为0,是0,视为相同元素不存。
元素的排序比较有两种方式:
1,元素自身具备自然排序,其实就是实现了Comparable接口重写了compareTo方法。
如果元素自身不具备自然排序,或者具备的自然排序不是所需要的,这时只能用第二种方式。
2,比较器排序,其实就是在创建TreeSet集合时,在构造函数中指定具体的比较方式。
需要定义一个类实现Comparator接口,重写compare方法。

5.1 HashSet

HashSet:哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode(),equals()方法。查询速度快。

注意:重点是哈希冲突是怎么解决的

5.2 重复元素去掉hashCode,equals

package cn.itcast.api.c.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import cn.itcast.domain.Student;

public class SetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        Set set = new HashSet();
        
        /*
//        去除了字符串中的重复元素。
        set.add("nba");
        set.add("java");
        set.add("haha");
        set.add("itcast");
        set.add("haha");
        set.add("java");
        set.add("java");
        set.add("java");
        set.add("itcast");*/
        
        /*
         * 
         * 为什么学生对象没有保证唯一性呢?
         * 通过对哈希表的分析。
         * 存储元素时,先调用了元素对象的hashCode()方法,而每个学生对象都是新建立的对象,
         * 所以hashCode值都不相同,也就不需要判断equals了。
         * 想要按照需求同姓名同年龄来保证学生对象的唯一性咋办?
         * 不能使用Object中hashCode方法,需要重新定义hashCode的算法内容。
         * 简单说:重写hashCode方法。
         */
        set.add(new Student("lisi1",21));
        set.add(new Student("lisi2",22));
        set.add(new Student("lisi1",21));
        set.add(new Student("lisi2",22));
        set.add(new Student("lisi1",21));
        
        "abc1".hashCode();
        
        for (Iterator it = set.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }

    }

}

 

 

5.3 TreeSet

|--TreeSet:可以对Set集合中的元素进行排序。使用的是二叉树结构。如何保证元素唯一性的呢?
使用的对象比较方法的结果是否为0,是0,视为相同元素不存。
元素的排序比较有两种方式:
1,元素自身具备自然排序,其实就是实现了Comparable接口重写了compareTo方法。
如果元素自身不具备自然排序,或者具备的自然排序不是所需要的,这时只能用第二种方式。
2,比较器排序,其实就是在创建TreeSet集合时,在构造函数中指定具体的比较方式。
需要定义一个类实现Comparator接口,重写compare方法

Comparable和comparator 其实是一种策略模式

演示TreeSet

package cn.itcast.api.c.set;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import cn.itcast.domain.Student;

public class TreeSetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
    
        //演示TreeSet,
        Set set = new TreeSet();
        /*
        set.add("nba");
        set.add("abc");
        set.add("java");
        set.add("aaa");
        */
        /*
         * TreeSet的add方法内部最终实现:
         * 需要将元素转成Comparable类型,为什么?因为这个类型具备排序的能力。
         * 这个类型中有一个专门为排序提供了一个compareTo方法。
         * 如果要让学生具备比较排序的功能,需要让学生扩展功能,实现Comparable接口。
         */
        set.add(new Student("lisi6",21));
        set.add(new Student("lisi8",22));
        set.add(new Student("lisi5",25));
        set.add(new Student("lisi3",23));
        set.add(new Student("lisi7",20));
        
        
        
        for (Iterator it = set.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }
    }
}

如果不重写comparable里面的方法报的异常

重写之后

 

/*
* 注意:在比较时,必须明确主次。主要条件相同,继续比较次要条件。
*/
int temp = this.age - stu.age;

return temp==0?this.name.compareTo(stu.name):temp;

 

 TreeSet比较结构

 这里好像二叉排序树

 

TreeSet comparator

package cn.itcast.api.c.set;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import cn.itcast.api.d.comparator.ComparatorByName;
import cn.itcast.domain.Student;

public class TreeSetDemo2 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //在创建TreeSet集合对象时明确比较器。
        Set set = new TreeSet(new ComparatorByName());
        /*
         * 想要按照学生的姓名排序,说明学生中的自然排序不是所需要的。
         * 这时只能使用比较器。ComparatorByName。
         */
        set.add(new Student("lisi6",21));
        set.add(new Student("lisi8",22));
        set.add(new Student("lisi5",25));
        set.add(new Student("lisi3",23));
        set.add(new Student("lisi7",20));
        
        for (Iterator it = set.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }

    }

}


 

 总结:

到此为止:再往集合中存储对象时,通常该对象都需要覆盖hashCode,equals,
同时实现Comparale接口,建立对象的自然排序。通常还有一个方法也会复写toString();

5.4 练习

package cn.itcast.api.c.set;

import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import cn.itcast.api.d.comparator.ComparatorByLength;

public class TreeSetTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        /*
         * 练习:要对字符串进行长度(由短到长)排序。
         * 思路:
         * 1,字符串之所以可以排序,因为是已经实现Comparable接口重写compareTo方法。
         * 建立了字符串的自然排序。
         * 2,但是自然排序不是需求中所需要的。咋办?
         * 只能使用比较器。需要自定义一个比较器。
         * 
         */
        Set set = new TreeSet(Collections.reverseOrder(new ComparatorByLength()));
        
        set.add("abc");
        set.add("haha");
        set.add("xixi");
        set.add("z");
        set.add("hiahia");
        
        for (Iterator it = set.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }

    }

}

5.5 LinkedHashSet

Hash查询快,但是查出来是没有顺序的。我想怎么存进去的,怎么取出来

这时要用到LinkedHashSet;

package cn.itcast.api.c.set;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        
        /*
         * 提高唯一性元素的查询效率,还想有序,可使用HashSet的子类LinkedHashSet.
         */
        Set set = new LinkedHashSet();
        
        set.add("abcd");
        set.add("hahahah");
        set.add("java");
        set.add("itcast");
        
        for (Iterator it = set.iterator(); it.hasNext();) {
            System.out.println(it.next());
        }

    }

}

 

5.6 foreach循环

package cn.itcast.api.e.foreach;

import java.util.ArrayList;
import java.util.List;

public class ForeachDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        /*
         * foreach:其实就是增强for循环。
         * 格式:
         * for(元素的数据类型  变量   : Collection集合or数组){}
         * 用于遍历Collection和数组。通常只能遍历元素,不要在遍历的过程中做对集合元素的操作。
         * 
         * 和老式的for循环有什么区别?
         * 注意:新for循环必须有被遍历的目标。目标只能是Collection或者是数组。
         * 建议:遍历数组时,如果仅为遍历,可以使用增强for如果要对数组的元素进行 操作,使用老式for循环可以通过角标操作。
         * 
         */
        
        List list = new ArrayList();
        list.add("itcast1");
        list.add("itcast2");
        list.add("itcast3");
        list.add("itcast4");
        
//        for (Iterator it = list.iterator(); it.hasNext();) {
//            Object obj = it.next();
//            System.out.println(obj);
//        }
        
        for(Object obj : list){//简化。
            System.out.println(obj);
        }

    }

}

 

5.7 查阅的小技巧

看集合对象的小技巧:★★★★★★
集合分体系。List Set
子类对象的后缀名是所属体系,前缀名是数据结构名称。
List:新出的子类都是以List结尾的,通常都是非同步的。
|--ArrayList :看到array,就知道数组,查询速度快。
|--LinkedList:看到link,就知道链表,增删速度快。

Set:
|--HashSet:看到hash,就知道哈希表,查询速度更快,并想到元素唯一,通过hashCode(),equals方法保证唯一性。
|--TreeSet:看到tree,就知道二叉树,可以排序,排序想到Comparable-compareTo Comparator--compare方法。

 

posted @ 2018-01-16 21:58  8亩田  阅读(223)  评论(0编辑  收藏  举报