Java学习之集合框架

一、集合框架的概述

1、概述:

1、简述:
所谓集合,就是为方便对多个对象的操作,对对象进行存储。集合就是存储对象最常用的一种方式。

2、集合与数组的区别:
数组:可存储同种类型的数据,但长度固定,也可存储基本类型的数据
集合:只可存储对象,长度可变,类型可以不同。

3、集合的特点:
只用于存储对象,长度可变,也可存不同类型的对象。
集合是一个接口,将每种容器的共性提取,形成的一个体系。

4、数据结构:
由于每种容器对数据的存储方式都各不相同,所以出现了不同的容器。此种存储方式称之为数据结构。

2、集合体系如图:

集合体系示意图

3、集合中的共性方法:

下面从增删改查等方面对这些共性发方法进行简单介绍:
说明:
a.add方法中的参数类型是Object,以便于接收任意类型的对象
b.集合中存储的都是对象的引用(即地址)。

1、增加:
add(Object obj); -----> 添加元素

2、删除:
remove(); -----> 删除集合中指定参数的元素
removeAll(); -----> 删除当前集合中与另一集合相同的元素,即只保留与另一集合不同的元素
clear(); -----> 清空集合中的元素,集合还存在

3、获取集合长度:
size(); -----> 获取集合长度,即集合元素的个数

4、修改:
set(int index,e); -----> 将指定位置(index)上的元素修改为给定的参数e

5、判断:
boolean contains(e); -----> 判断给定元素e是否存在于集合中

6、迭代器:
iterator(); -----> 集合取出元素的方式
boolean hasNext(); -----> 判断是否还有下一个元素
next(); -----> 取出下一个元素

示例:

import java.util.*;  
  
class CollectionDemo   
{  
    public static void sop(Object obj)  
    {  
        System.out.println(obj);  
    }  
      
    public static void main(String[] args)   
    {  
        base_method();  
        sop("------------------");  
        method2();  
        sop("------------------");  
        method_get();  
    }  
      
    public static void base_method()  
    {  
        //创建一个集合容器,使用Collection接口的子类,ArrayList  
        ArrayList al = new ArrayList();  
        //1.添加元素--->add(Object obj),多态   
        al.add("java01");  
        al.add("java02");  
        al.add("java03");  
        al.add("java04");  
  
        //打印原集合  
        sop("原集合" + al);  
  
        //3.删除元素  
        al.remove("java02");  
          
        //清空集合中的元素  
        al.clear();  
  
        //4.判断元素  
        //判断集合中是否存在某个元素:contains()  
        sop("是否存在java03:" + al.contains("java03"));  
        //判断集合是否为空:isEmpty()  
        sop("判断集合是否为空:" + al.isEmpty());  
  
  
        //2.获取个数,集合长度  
        sop("size :" + al.size());  
  
        //打印改变后集合  
        sop(al);  
  
  
        System.out.println("Hello World!");  
    }  
  
    public static void method2()  
    {  
        //创建另一个新集合  
        ArrayList at1 = new ArrayList();  
        at1.add("java01");  
        at1.add("java02");  
        at1.add("java03");  
        at1.add("java04");  
  
        //打印原集合  
        sop("原集合at1:" + at1);  
  
        ArrayList at2 = new ArrayList();  
        at2.add("java01");  
        at2.add("java02");  
        at2.add("java05");  
        at2.add("java06");  
        sop("原集合at2:" + at2);  
  
        //removeAll()--->只保留和at2不相同的元素。  
        at1.removeAll(at2);  
        sop("remove后at1:" + at1);  
        sop("now集合at2:" + at2);  
  
  
        //取两个集合的交集,at1中只保留交集的部分  
        at1.retainAll(at2);  
          
        sop("取完交集后的at1:" + at1);  
    }  
  
    public static void method_get()  
    {  
        //创建另一个新集合  
        ArrayList at1 = new ArrayList();  
        at1.add("java01");  
        at1.add("java02");  
        at1.add("java03");  
        at1.add("java04");  
  
        //打印原集合  
        sop("原集合at1:" + at1);  
  
        //获取迭代器,用于去除集合中的元素  
        Iterator it = at1.iterator();  
  
        while (it.hasNext())  
        {  
            sop(it.next());  
        }  
    }  
}

4、Collection接口包含的子类

Collection接口包含List与Set等子类
List:元素是有序的,元素可重复,因该集合体系有索引
Set:元素是无序的,元素不可重复

下面具体总结一下关于两种集合:

二、List集合

1、概述:

List集合包含三个子类:ArrayList、LinkedList以及Vector等。
具体区别如下:
1、ArrayList:底层的数据结构是数组结构
特点:查询速度很快,因为有索引(角标),但增删速度稍慢。是线程不同步的。

2、LinkedList:底层使用的是链表数据结构
特点:增删速度很快,但查询速度稍慢,因为每一个元素都链接到前一元素。

3、Vector:底层是数组结构,JDK1.0出现,比较老。
特点:增删查询都很慢,被ArrayList替代了,线程是同步的。

2、对于List集合特有的方法:

凡是可操作角标的方法都是该体系特有的方法,基本方法和Collection中的一样。
1、增加:
add(int index,e); -----> 在指定位置增加给定的元素
addAll(int index,Collection); -----> 在指定位置增加给定集合中的所有元素,若省略位置参数,则在当前集合的后面依次添加元素

2、删除:
remove(int index); -----> 删除集合中指定位置上的元素

3、修改:
set(int index,e); -----> 将指定位置(index)上的元素修改为给定的参数e

4、查询:
get(int index); -----> 获取指定位置上的元素
indexOf(e); -----> 通过指定元素获取其在集合中的位置
subList(int from,int to); -----> 获取从from到to位置上的元素
Iterator listIterator(); -----> 返回Iterator接口类型值

注:
1、listIterator是List特有的迭代器,是Iterator子接口。在迭代时,不可通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModficationException异常。
所以,在迭代时,只能用迭代器的方法操作,可Iterator方法是有限的,若想要其他操作如增删改写等,就需要使用子接口,即ListIterator,该接口只能通过List集合的listIerator方法获取。

2、在迭代时,循环中的next()调用一次,就要对hasNext判断一次,不可判断一次调用两次。

3、List集合判断元素是否相同,一句的是元素的equals方法,其中,contains中就是调用的equals方法。

示例:

import java.util.*;  
class ListDemo   
{  
    public static void sop(Object obj)  
    {  
        System.out.println(obj);  
    }  
      
    public static void main(String[] args)   
    {  
        methodAdd();  
        //methodListIterator();  
    }  
  
    public static void methodAdd()  
    {  
        //创建一个集合容器,使用Collection接口的子类,ArrayList  
        ArrayList list = new ArrayList();  
        //1.添加元素--->add(Object obj),多态   
        list.add("java01");  
        list.add("java02");  
        list.add("java03");  
        list.add("java04");  
  
        ArrayList list2 = new ArrayList();  
        //1.添加元素--->add(Object obj),多态   
        list2.add("java05");  
        list2.add("java06");  
        list2.add("java07");  
        list2.add("java08");  
  
        //打印原集合  
        sop("原集合:" + list);  
        sop("------------------");  
  
        //1.在某一个位置上添加元素:add(int index,"新元素")  
        list.add(1,"java001");  
        sop("增加后的集合:" + list);  
        sop("---------");  
        list.addAll(1,list2);  
        sop("在list中1位置后添加list2:" + list);  
        sop("------------------");  
  
        //2.删除指定位置上的元素:  
        list.remove(2);  
        sop("删除后的集合:" + list);  
        sop("------------------");  
  
        //3.改变某一位置上的元素:set(int index,"要改成的元素")  
        list.set(2,"java007");  
        sop("改变角标为2的元素后的元素:" + list);  
        sop("------------------");  
  
        //4.获取元素:get()  
        list.get(1);  
        sop("获取角标为1上的元素:" + list.get(1));  
        sop("------------------");  
  
        //通过某个元素获取其在集合中的位置--indexOf("查找的元素")  
        int m = list.indexOf("java007");  
        sop("获取“java007”所在的位置:" + m);  
  
        //获取从某个位置到另一位置上的元素subList()  
        List l = list.subList(1,3);  
        sop("获取从位置1到3上的元素:" + l);  
        sop("------------------");  
  
        //4.获取全部元素  
        //get方法的for循环  
        sop("get方法:");  
        for (int i=0;i<list.size();i++)  
        {  
            sop("list(" + i + ")" + list.get(i));  
        }  
        sop("------------------");  
  
        //迭代器方法:Iterator()  
        for (Iterator it = list.iterator();it.hasNext(); )  
        {  
            sop("next:" + it.next());  
        }  
        sop("------------------");  
}  
  
    public static void methodListIterator()  
    {  
        //演示列表迭代器:  
        ArrayList list = new ArrayList();  
        //1.添加元素--->add(Object obj),多态   
        list.add("java01");  
        list.add("java02");  
        list.add("java03");  
        list.add("java04");  
  
        //打印原集合  
        sop("原集合:" + list);  
        sop("------------------");  
  
          
  
        //在迭代过程中,准备添加或删除元素  
        for (ListIterator it = list.listIterator();it.hasNext(); )  
        {  
            Object obj = it.next();  
            if (obj.equals("java01"))  
                it.remove();  
            else if(obj.equals("java02"))  
                it.add("增加java200");  
            else if(obj.equals("java03"))  
                it.set("修改为java300");  
            sop("obj:" + obj);  
        }  
        sop("list :" + list);  
    }  
}

3、Vector类:

Vector中有种特殊的取出方式,即为枚举
1、枚举和迭代器十分相似,其实两者是一样的,由于枚举的名称以及方法名都过长,因此,就被迭代器取代了。这里就不过多的介绍了。

4、LinkedList类特有方法:

一)JDK1.6之前的方法
1、增加:
addFirst(obj); -----> 在集合头部添加给定的元素
addLast(obj); -----> 在集合尾部添加给定的元素

2、获取:
getFirst(); -----> 获取集合第一个元素,若集合中没有元素,则出现NoSuchElementException
getLast(); -----> 获取集合最后一个元素,若集合中没有元素,则出现NoSuchElementException

3、删除:
removeFirst(); -----> 获取并删除集合第一个元素,若集合中没有元素,则出现NoSuchElementException
removeLast(); -----> 获取并删除集合最后一个元素,若集合中没有元素,则出现NoSuchElementException

二)JDK1.6出现的替代方法:
1、增加:
offerFirst(obj); -----> 在集合头部添加给定的元素
offerLast(obj);``` -----> 在集合尾部添加给定的元素

2、获取:
peekFirst(); -----> 获取集合第一个元素,若集合中没有元素,则返回null
peekLast(); -----> 获取集合最后一个元素,若集合中没有元素,则返回null

3、删除:
pollFirst(); -----> 获取并删除集合第一个元素 ,若集合中没有元素,则返回null
pollLast(); -----> 获取并删除集合最后一个元素,若集合中没有元素,则返回null

三、Set 集合

1、概述:

1、Set集合的特点:
1)集合中的元素师无需的(存入和取出的顺序不一定一致),且元素不可重复。
2)Set集合的功能和Collection集合的是一样的,并没有什么特别的方法。

这里主要说一下关于HashSet和TreeSet两种集合的方法和特点:

2、HashSet类

1、特点:
底层数据结构时哈希表,且元素取出方式只有迭代器方法

2、哈希表简介:
1)哈希表是按照哈希值的大小进行排列的,如果两个哈希值不同,则大的值放后面;如果两个哈希值相同,则再用equals方法比较两个元素的对象是否相同,如果不同,则将第二个值顺延,两个值串起来,放在同一个位置上。

2)取值时是按照哈希值取出来的。

3)哈希值的取值方式:哈希值存入哈希表中,哈希表也称散列表。散列表是存放记录的数组。具体来说,散列表是根据散列函数H(Key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象”,作为这条记录在表中的存储位置,这种表表称为散列表,这一映象过程就称为散列造表或散列,所存储位置称为散列地址(这是百度百科上的内容)。我的理解是:存入的对象的地址是通过提取其信息摘要,通过散列函数计算而获得的一个关键码(Key)即哈希值,然后将这个值存入哈希表,而哈希表的存值方式是按照哈希值的大小顺序存储的,并且在这个哈希表中有自己的索引,但是哈希表的取值方式并不是按照索引的方式取出的。取出方式是按照哈希表中特有的算法取出的哈希值(注意,现在说的是哈希值,不是元素的取出),这些算法有直接寻址法、折叠法、平方取中法以及其他的一些方法等等。具体是按哪种算法查找的,我并不太清楚,所以,取出的哈希值可能就不是按照哈希值的大小顺序取出的了。

3、HashSet如何保证元素的唯一性:
通过元素的两个方法hasCode和equals方法来完成的。
如果元素的hashCode的值相同,才会判断equals是否为true。如果元素的hashCode值不相同,就不会调用equals方法了。
注:
对于判断元素是否存在和删除(或添加)。依赖的方法是元素的hashcode和equals方法。

示例:

/* 
 
思路: 
    1、对人描述,将数据封装进对象 
    2、定义容器,将人存入 
    3、取出 
    4、移除 
*/  
  
import java.util.*;  
  
class TypeException extends Exception  
{  
    TypeException(String message)  
    {  
        super(message);  
    }  
}  
class Person  
{  
    private String name;  
    private int age;  
    Person(String name,int age)  
    {  
        this.name = name;  
        this.age = age;  
    }  
    public String getName()  
    {  
        return name;  
    }  
    public int getAge()  
    {  
        return age;  
    }  
    public int hashCode()  
    {  
        return this.name.hashCode()+age*39;  
    }  
    public boolean equals(Object obj)  
    {  
        try  
        {  
            if (!(obj instanceof Person))  
                throw new TypeException("NoSuchTypeException");  
        }  
        catch (TypeException e)  
        {  
            System.out.println(e.toString());  
        }  
        Person p = (Person)obj;  
        return this.name.equals(p.name) && this.age == p.age;  
    }  
}  
class HashDemo   
{  
    public static void sop(Object obj)  
    {  
        System.out.println(obj);  
    }  
  
    public static void printE(HashSet hs)  
    {  
        Iterator it = hs.iterator();  
  
        while (it.hasNext())  
        {  
            Person p = (Person)it.next();  
            sop(p.getName() + "--" + p.getAge());  
        }  
    }  
  
    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("a3",13));  
        sop("原集合:");  
        printE(hs);  
        sop("移除后的集合:");  
        hs.remove(new Person("a3",13));  
        printE(hs);  
    }  
}

3、TreeSet类:

1、特点:
1)底层的数据结构为二叉树结构(红黑树结构)

2)可对Set集合中的元素进行排序,是因为:TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。
java中的很多类都具备比较性,其实就是实现了Comparable接口。

注意:排序时,当主要条件相同时,按次要条件排序。

3)二叉树示意图:
我通过对二叉树分布的测验,画了一个图,不知对否,仅供参考
对于存入时每个元素的比较,并不是连续排下来的,而是随着元素的个数而改变的,如图中所示:
第①步:22比较完了,如图①,之后会重新分布
第②部:以22为顶部,开始比较,如图②
第③步:比完第一个33后的图示,当比第二个33重复元素的时候,又重新分布了
第④步:分布如图,第二个33是按这个如比较的。


二叉树示意图

2、保证元素唯一性的依据:
实现的compareTo方法的返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入。

3、两种比较方式:
排序有两个要素:元素和集合
1)第一种排序方式:自然排序
让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法,这种方式也称为元素的自然排序或默认排序方式。

示例:

/* 
第一种排序方式:自然排序,实现Comparable接口,重写compareTo方法 
需求: 
向TreeSet集合中存储自定义对象学生 
按照学生的年龄进行排序 
*/  
import java.util.*;  
//此接口强制让Student实现比较性  
class Student implements Comparable   
{  
    //定义Student私有属性  
    private String name;  
    private int age;  
    //构造Student函数,初始化  
    Student(String name,int age)  
    {  
        this.name = name;  
        this.age = age;  
    }  
    //公共访问方法,访问私有属性  
    public String getName()  
    {  
        return name;      
    }  
    public int getAge()  
    {  
        return age;  
    }  
    //复写Comparator中的compare方法,自定义比较器  
    public int compareTo(Object obj)  
    {  
        //判断是否属于Student类型,否则抛异常  
        if (!(obj instanceof Student))  
            throw new RuntimeException("NotSuchTypeException");  
        //将Object类对象强转为Student类  
        Student s = (Student)obj;  
          
        //System.out.println(this.age + "--compare-" + s.age);//测试用,查看比较情况  
  
        //按年龄大小比较,相同则比较姓名大小,不同返回两年龄之差  
        if (this.age == s.age)  
        {  
            return this.name.compareTo(s.name);  
        }  
        else if (this.age <s.age)  
            return this.age-s.age;  
        return this.age-s.age;  
    }  
    /* 
    //如果按照存入顺序输出 
    public int compareTo() 
    { 
        return 1;//改为-1则按倒叙输出 
    } 
    */  
}  
//测试  
class TreeSetTest  
{  
    public static void main(String[] args)   
    {  
        //创建集合,并添加元素  
        TreeSet ts = new TreeSet();  
        ts.add(new Student("li01",25));  
        ts.add(new Student("li02",20));  
        ts.add(new Student("li01",22));  
        ts.add(new Student("li05",24));  
        ts.add(new Student("li08",40));  
        //打印集合中元素  
        printE(ts);  
          
        System.out.println("Hello World!");  
    }  
  
    //定义打印集合中元素的功能  
    public static void printE(TreeSet ts)  
    {  
        //迭代器方法获取  
        Iterator it = ts.iterator();  
      
        while (it.hasNext())  
        {  
            //将返回的元素(Object类)强转为Student类  
            Student s = (Student)it.next();  
            System.out.println(s.getName() + "---" + s.getAge());  
        }  
    }  
}

2)第二种排序方式:比较器
当元素自身不具备比较性是,或者具备比较性,却不是所需要的,这时就需要让集合自身具备比较性。在集合初始化时就有了比较方式(即参阅构造函数)。
当两种排序方式都存在时,以比较器为主。

如何构造比较器:定义一个类,实现Comparator接口,覆盖compare方法。

注:字符串本身具备比较性,但是它的比较方式可能不是所需要的,这时,就只能使用比较器了。

示例:

import java.util.*;  
//此接口强制让Student实现比较性  
class Student implements Comparable  
{  
    //定义Student私有属性  
    private String name;  
    private int age;  
    //构造Student函数,初始化  
    Student(String name,int age)  
    {  
        this.name = name;  
        this.age = age;  
    }  
    //公共访问方法,访问私有属性  
    public String getName()  
    {  
        return name;  
    }  
    public int getAge()  
    {  
        return age;  
    }  
  
    //复写Comparator中的compare方法,自定义比较器  
    public int compareTo(Object obj)  
    {  
        //判断是否属于Student类型,否则抛异常  
        if (!(obj instanceof Student))  
            throw new RuntimeException("NotSuchTypeException");  
        //按年龄大小比较,相同则比较姓名大小,不同返回两年龄之差  
        Student s = (Student)obj;  
        if (this.age > s.age)  
            return this.age-s.age;  
        else if (this.age == s.age)  
        {  
            return this.name.compareTo(s.name);  
        }  
        return this.age-s.age;  
    }  
          
}  
  
//定义比较器,实现Comparator接口  
class MyCompare implements Comparator  
{  
    //重写Comparator中的compare方法,按姓名顺序排序  
    public int compare(Object o1,Object o2)  
    {  
        //判断给定对象是否为Student类,否则抛异常  
        if (!((o1 instanceof Student) && (o2 instanceof Student)))  
            throw new RuntimeException("NotSuchTypeException");  
        //将给定对象强转为Student类  
        Student s1 = (Student)o1;  
        Student s2 = (Student)o2;  
        //比较名字,返回数值,相同则比较年龄  
        int n = s1.getName().compareTo(s2.getName());  
        if (n == 0)  
            return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));  
        return n;  
    }  
}  
//测试  
class TreeSetComDemo   
{  
    public static void main(String[] args)   
    {  
        //TreeSet ts = new TreeSet();  
  
        //创建集合,加入接口类参数,并添加元素  
        TreeSet ts = new TreeSet(new MyCompare());  
        ts.add(new Student("li01",25));  
        ts.add(new Student("li02",20));  
        ts.add(new Student("li01",22));  
        ts.add(new Student("li05",24));  
        ts.add(new Student("li08",40));  
  
        //打印集合中元素  
        printE(ts);  
    }  
      
    //定义打印集合中元素的功能  
    public static void printE(TreeSet ts)  
    {  
        //迭代器方法获取  
        Iterator it = ts.iterator();  
      
        while (it.hasNext())  
        {  
            //将返回的元素(Object类)强转为Student类  
            Student s = (Student)it.next();  
            System.out.println(s.getName() + "---" + s.getAge());  
        }  
    }  
}

四、Map 集合

1、概述:

1、简述:
Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key)

2、特点:
1)该集合存储键值对,一对一对往里存
2)要保证键的唯一性。

2、方法简介:

Map集合中的方法和上面集合的方法是很相似的,这里不一一都具体说明了,用示例的形式体现一下:
1、添加: 添加单个元素:put(k key,V value); 添加一个集合:putAll(Map<? extends K,? extends V> m)

2、删除: 获取并移除:remove(Object key); 清空集合中元素:clear (Object key)

3、判断: 判断集合是否为空: isEmpty() ; 键对应的值是否存在:containsKey(Object key); 值对应的键是否存在:containsValue(Object obj) ----> 返回boolean类型

4、获取: 获取单个元素:get(Object key); 获取长度:size(); 获取Map集合中的所有值(value),返回Conllection集合。

注:
a.也可以通过get()方法的返回值来判断一个键是否存在,通过返回null来判断。
b.其中put方法:如果出现添加相同的键,那么后添加的值会覆盖原有键对应的值,并且该方法返回被覆盖的值即原值。

示例:

/* 
Map集合方法 
*/  
import java.util.*;  
class MapDemo   
{  
    public static void sop(Object obj)  
    {  
        System.out.println(obj);  
    }  
    public static void main(String[] args)   
    {  
        //创建Map集合,并添加元素  
        Map<Integer,String> map = new HashMap<Integer,String>();  
        map.put(1,"zhangsan");  
        map.put(2,"lisi");  
        map.put(3,"wangwu");  
        map.put(4,"heihei");  
        map.put(5,"xixi");  
        //获取长度  
        int n = map.size();  
        //打印元素  
        sop("原集合:" + map + "\n长度为:" + n);  
        sop("---------------------------------------");  
        //创建新集合,并添加元素  
        Map<Integer,String> m = new HashMap<Integer,String>();  
        m.put(7,"zann");  
        m.put(9,"hewi");  
        m.put(13,"wangfei");  
        m.put(14,"huxi");  
        m.put(10,"anch");  
        //用putAll将元素添加到原集合中  
        map.putAll(m);  
        sop("putAll --新集合:" + map);  
        sop("----------------------------------");  
        //删除元素  
        sop("remove:" + map.remove(01));  
        sop("新集合:" + map);  
        sop("----------------------------------");  
        /* 
        //清空集合中的元素 
        map.clear(); 
        sop("新集合:" + map); 
        //判断是否为空集合 
        boolean be = map.isEmpty(); 
        sop("isEmpty ,null? :" + be); 
        sop("----------------------------------"); 
        */  
  
        //判断元素是否存在  
        boolean bk = map.containsKey(01);  
        boolean bv = map.containsValue("wangwu");  
        sop("判断:\n01?:" + bk + "-----  wangwu?:" + bv);  
        sop("----------------------------------");  
          
        //获取元素:get  
        String s = map.get(01);  
        String s1 = map.get(02);  
        //Integer i =  map.get("lisi");  
        //Integer i2 = map.get("zhangsan");  
        sop(map.get("lisi"));  
        sop(map.get("zhangsan"));   
        sop("获取元素get:01:" + s + ",02:" + s1);  
        sop("-----------------------------------------------");  
        //获取集合中的所有元素:Value  
        Collection<String>  coll = map.values();  
        sop("value--获取集合中所有元素:" + coll);  
        sop("----------------------------------");  
    }  
}

3、Map集合中的子类:

1、HashTable:特点 -- > 底层是哈希表数据结构,不可存入null键和null值。该集合是线程同步的,效率较低

2、HashMap:特点 -- > 底层是哈希表数据结构,允许使用null值和null键。该集合是线程同步的,效率较高

3、TreeMap:特点 -- > 底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键值进行排序,和Set很像,其实,Set集合的底层就是使用了Map集合。

4、两种获取集合元素的方法:

重点说一下获取方法中的两个:keySet()和entrySet()方法

1、keySet()方法获取元素
原理:将Map集合中的所有键存入到Set集合中,因为Set集合具备迭代器,所以可以用迭代方式取出所有的键,再根据get方法获取每一个键对应的值。
简单说就是:Map集合---->Set集合 ---->迭代器取出

示例:

//keySet集合测试  
  
import java.util.*;  
class KeySetDemo   
{  
    public static void main(String[] args)   
    {  
        //创建Map集合,并添加元素  
        Map<Integer,String> map = new HashMap<Integer,String>();  
        map.put(2,"zhangsan");  
        map.put(6,"lisi");  
        map.put(3,"wangwu");  
        map.put(4,"heihei");  
        map.put(5,"xixi");  
        //获取map集合中的所有键的Set集合  
        Set<Integer> keySet = map.keySet();  
        //有了Set集合就可以获取其迭代器,取值  
        Iterator<Integer> it = keySet.iterator();  
        while (it.hasNext())  
        {  
            Integer i = it.next();  
            String s = map.get(i);  
            System.out.println(i + " = " + s);  
        }  
    }  
}

2、entrySet()方法获取元素:
原理:
将Map集合中的映射关系存入到了Set集合中,而这个映射关系的数据类型是Map.Entry,在通过迭代器将映射关系存入到Map.Entry集合中,并通过其中的getKey()和getValue()放取出键值。

示例:

/* 
entrySet取出方式: 
*/  
import java.util.*;  
class EntrySetDemo  
{  
    public static void main(String[] args)   
    {  
        //创建集合,存入元素  
        Map<String,String> map = new HashMap<String,String>();  
        map.put("01","lisi1");  
        map.put("02","lisi2");  
        map.put("03","lisi3");  
        map.put("04","lisi4");  
        //获取map集合中的所有键,存入到Set集合中,  
        Set<Map.Entry<String,String>> entry = map.entrySet();  
        //通过迭代器取出map中的键值关系,迭代器接收的泛型参数应和Set接收的一致  
        Iterator<Map.Entry<String,String>> it = entry.iterator();  
        while (it.hasNext())  
        {  
            //将键值关系取出存入Map.Entry这个映射关系集合接口中  
            Map.Entry<String,String>  me = it.next();  
            //使用Map.Entry中的方法获取键和值  
            String key = me.getKey();  
            String value = me.getValue();  
            System.out.println(key + " : " + value);  
        }  
    }  
}

补充:关于Map.Entry
Map是一个接口,其实,Entry也是一个接口,它是Map的子接口中的一个内部接口,就相当于是类中有内部类一样。为何要定义在其内部呢?

原因:
a.Map集合中村的是映射关系这样的两个数据,是先有Map这个集合,才可有映射关系的存在,而且此类关系是集合的内部事务。
b.并且这个映射关系可以直接访问Map集合中的内部成员,所以定义在内部。

5、Map集合的应用及扩展:

1、何时使用Map集合:当量数据之间存在着映射关系的时候,就应该想到使用Map集合。

2、示例:
获取该字符串中的字母出现的次数,如:"sjokafjoilnvoaxllvkasjdfns";希望打印的结果是:a(3)c(0).....
通过结果发现,每个字母都有对应的次数,说明字母和次数之间有映射关系。

测试如下:

import java.util.*;  
class MapTest  
{  
    public static void main(String[] args)   
    {  
        String s = "abcsjokafjoilnvoaxllvkasjdfnsde 0[fga8/-abbdc";  
        String str = LetterNum(s);  
        System.out.println(str);  
    }  
  
    public static String LetterNum(String str)  
    {  
        //将字符串转换成字符数组,因为对每个字母进行操作  
        char[] ch = str.toCharArray();  
        //定义一个Map集合,因为打印结果的字母有顺序,所以使用TreeMap集合  
        TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();  
        int count = 0;  
        //遍历字符数组,将每一个字母作为键去查map集合,  
        for (int i=0;i<ch.length;i++)  
        {  
            //判断集合是否含有其他非字母,是则再次循环  
            if (!(ch[i]>= 'a' && ch[i] <= 'z' || ch[i] >= 'A' && ch[i] <= 'Z'))  
                continue;  
            //取出键对应的值,不为则计数器加1,存入集合,并将计数器清零,用于下一个字母  
            Integer value = tm.get(ch[i]);  
            if (value != null)  
                count = value;  
            count++;  
            tm.put(ch[i],count);  
            count = 0;  
        }  
        //创建字符串容器,存入取出的键值即按顺序排列的字符串  
        StringBuilder sb = new StringBuilder();  
        //迭代器取出相应键值,并存入字符串容器  
        Iterator<Map.Entry<Character,Integer>> it = tm.entrySet().iterator();  
        while (it.hasNext())  
        {  
            Map.Entry<Character,Integer> me = it.next();  
            Character key = me.getKey();  
            Integer value = me.getValue();  
            sb.append(key + "(" + value + ")");  
        }  
        return sb.toString();  
    }  
}

6、集合映射的扩展:

在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。
示例如下:

/* 
Map扩展:一对多的映射关系 
如:学校中的  班级:学生:学号三者关系 
思路, 
    先创建大的集合,学校,如school 
    其中包含班级这个小集合,如room 
    班级中包含的学生有姓名,如name 
                学生有学号,如id 
*/  
import java.util.*;  
//创建学生类,定义私有属性  
class Student  
{  
    private String name;  
    private String id;  
    Student(String name,String id)  
    {  
        this.name = name;  
        this.id = id;  
    }  
    //复写toString方法,给出指定字符串形式  
    public String toString()  
    {  
        return name + ":" + id;  
    }  
}  
//测试  
class MapsDemo  
{  
    public static void main(String[] args)   
    {  
        //创建一个学校,里面有班级  
        HashMap<String,HashMap<String,String>> czbk = new HashMap<String,HashMap<String,String>>();  
        //创建两个班级,里面有学生  
        //基础班  
        HashMap<String,String> base = new HashMap<String,String>();  
        //预热班  
        HashMap<String,String> adv = new HashMap<String,String>();  
        //将信息分别加入集合  
        //学校中的班级信息  
        czbk.put("Base",base);  
        czbk.put("Adv",adv);  
        //基础班中的学生信息  
        base.put("01","BS01");  
        base.put("02","BS02");  
        base.put("03","BS03");  
        //提高班中的学生信息  
        adv.put("01","ADV01");   
        adv.put("02","ADV02");   
        adv.put("03","ADV03");  
        //调用取出信息的方法  
        String all = getAll(czbk);  
        System.out.println("ALL: \n" + all);  
    }  
  
    //定义取出方法  
    //定义取出学校中班级的方法,并调用取出学生信息方法  
    public static String getAll(HashMap<String,HashMap<String,String>> school)  
    {  
        //定义存储班级信息字符串容器  
        StringBuilder sb = new StringBuilder();  
        //初始化班级为空  
        String room = null;  
        //将学校中的班级存入Set集合,并用迭代器获取  
        Set<String> keySet = school.keySet();  
        Iterator<String> it = keySet.iterator();  
        while(it.hasNext())  
        {  
            room = it.next();  
            //取出班级中的学生信息也放在容器中  
            HashMap<String,String>  hm = school.get(room);  
            //将班级中的学生信息字符串形式存入字符串容器中  
            sb.append(room + ":\n"+ getRoom(hm) );  
        }  
        //返回一个容器字符串,为学生信息  
        return sb.toString();  
    }  
    //定义取出班级中学生信息的方法,被上面的方法调用  
    public static String getRoom(HashMap<String,String> room)  
    {  
        //定义存储学生信息的字符串容器  
        StringBuilder sb = new StringBuilder();  
        //将班级中的学生信息存入Set集合,并用迭代器获取  
        Set<Map.Entry<String,String>> entrySet = room.entrySet();  
        Iterator<Map.Entry<String,String>> it = entrySet.iterator();  
        while(it.hasNext())  
        {  
            //将映射关系存入Map.Entry的集合中,并获取相应键值  
            Map.Entry<String,String> me = it.next();  
            String key = me.getKey();  
            String value = me.getValue();  
            //将学生信息存入到字符串容器中  
            sb.append(key + "::" + value + "\n");  
        }  
        //放回存有学生信息的字符串容器  
        return sb.toString();   
    }  
}

集合间区别

一、List接口

List接口对Collection进行了简单的扩充,它的具体实现类常用的有ArrayList和LinkedList。
你可以将任何东西放到一个List容器中,并在需要时从中取出。

ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,而LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。在具体应用时可以根据需要自由选择。

前面说的Iterator只能对容器进行向前遍历,而ListIterator则继承了Iterator的思想,并提供了对List进行双向遍历的方法。

二、Set接口

Set接口也是Collection的一种扩展。

而与List不同的是,在Set中的对象元素不能重复,也就是说你不能把同样的东西两次放入同一个Set容器中。

它的常用具体实现有HashSet和TreeSet类。

HashSet能快速定位一个元素,但是你放到HashSet中的对象需要实现hashCode()方法,它使用了前面说过的哈希码的算法。

而TreeSet则将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,这就用到了集合框架提供的另外两个实用类Comparable和Comparator。

一个类是可排序的,它就应该实现Comparable接口。有时多个类具有相同的排序算法,那就不需要在每分别重复定义相同的排序算法,只要实现Comparator接口即可。

集合框架中还有两个很实用的公用类:Collections和Arrays。
Collections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用的方法,Arrays则是对一个数组进行类似的操作。

三、Map

Map是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。

对于键对象来说,像Set一样,一个Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。

当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求。你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。

Map有两种比较常用的实现:HashMap和TreeMap。
HashMap也用到了哈希码的算法,以便快速查找一个键,
TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。

键和值的关联很简单,用pub(Object key,Object value)方法即可将一个键与一个值对象相关联。用get(Object key)可得到与此key对象所对应的值对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 概述 Java集合框架由Java类库的一系列接口、抽象类以及具体实现类组成。我们这里所说的集合就是把一组对象组织到...
    absfree阅读 1,243评论 0 10
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,571评论 18 399
  • Java集合框架 Java平台提供了一个全新的集合框架。“集合框架”主要由一组用来操作对象的接口组成。不同接口描述...
    小石38阅读 356评论 0 0
  • Collection ├List │├LinkedList │├ArrayList │└Vector │└Stac...
    AndyZX阅读 869评论 0 1
  • 八月十五,中秋月圆。 每月都有一次月圆的时候,全年共有十二次圆月。但,国人好似对八月十五——中秋的圆月,有着特别的...
    自由心空阅读 771评论 4 5