集合框架

来源:互联网 发布:零基础学编程 先学什么 编辑:程序博客网 时间:2024/04/28 14:28


一、集合类概述

1.为什么出现集合类?

    面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

2.数组和集合类都是容器,有什么不同?

    数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。

    数组中可以存储基本数据类型,集合只能存储对象。

3.集合体系

    java集合类主要负责保存、盛装数据,因此集合类也称容器类。根据数据存储方式的不同,定义了许多容器。java集合类分为:set、list、map。其中set代表无序、不可重复的集合;list代表有序、可重复的集合。map代表具有映射关系的集合。

    java集合类主要由Collection和Map两个接口派生,是集合框架的根接口。下面是java中集合类的关系图:


Collcetion集合框架

      |-----List :内部元素是有序的,元素可以重复。因为该集合体系有索引。

      |        |-ArrayList:底层的数据结构使用的是数组结构。

      |        |           特点:查询速度很快,但是增删很慢,线程不同步。

      |        |-LinkedList:底层使用的是链表数据结构。

      |        |            特点:增删速很度快,但是查询稍慢。

      |        └-Vector:底层是数组数据结构,线程同步,被ArrayList代替了。因为效率低。

      |

      └-----Set :内部元素是无序的,不可以重复,线程不同步。(存入和取出的顺序不一定一致)。

               |-HashSet:底层数据结构是哈希表,线程不安全,不同步。

               |        HashSet是如何保证元素唯一性的呢?

               |         答:是通过判断元素的两个方法hashCode()和equals()来完成。

               |             如果元素的HashCode值相同,才会判断epuals()是否为true

               |             如果元素的HashCode值不同,不会调用epuals()。

               |
               |         注意:对于判断元素是否存在,以及增删等操作,依赖的方法是元素的

               |         hashCode()和epuals()方法。

               |

               └-TreeSet:-可以对Set集合中的元素进行排序。底层数据结果是二叉树。

                          -保证元素唯一性的依据:compareTo方法return 0。

                          -TerrSet排序的第一种方式:让元素自身具备比较性。

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

                          -TerrSet排序的第一种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。

                             这时就需要让集合自身具备比较性。在集合初始化时,就有了比较方式。


        Map 映射:内部元素是无序的,该集合存储键值对,一对一对存储的,保证键的唯一性。

              |-Hashtable:底层是哈希表数据结构,不能存入null键null值,此集合线程同步。JDK1.0 效率低。

              |-HashMap:底层是哈希表数据结构,可以存入null键null值,此集合线程不同步。JDK1.2 效率高。

              └-TreeMap:底层是二叉树数据结构,此集合线程不同步,可以用于给map集合中的键进行排序。

4.集合框架的共性方法

    集合框架的共性功能通过Collection定义。

    (1)添加

        add(e);

        addAll(collection);

    (2)删除

        remove(e);

        removeAll(collection);

        clear();

    (3)判断

        contains(e);

        isEmpty();

    (4)获取

        iterator();迭代器

        size();

    (5)获取交集

        retainAll();

    (6)集合变数组

        toArray();

注意:

    (1)add方法的参数类型是Object,以便于接收任意类型对象。

    (2)集合中存储的都是对象的引用(地址),不是对象本身。

    (3)迭代器是取出方式,会直接访问集合中的元素,所以将迭代器通过内部类的形式来进行描述。通过容器的iterator()方法获取该内部类的对象。

二、List集合

    List集合代表一个有序集合。集合中的每个元素都有其对应的顺序索引。Arraylist和vector是list接口的两个典型实现。他们之间的显著区别就是:vector是线性安全的,而arraylist不是。它们两个都是基于数组实现的list类。List还有一个基于链表实现的LinkedList类。当插入、删除元素的速度非常快。这个类比较特殊,功能也特别多,即实现了List接口,也实现了Dueue接口(双向队列)。可以当成双向队列使用,也可以当成栈使用。

1.list特有方法(凡是可以操作角标的方法都是该体系特有的方法。)

    (1)增:add(index,element); 向列表的尾部添加指定的元素

    addAll(index,Collection);

    (2)删:remove(index);移除列表中指定位置的元素。

    (3)改:set(index,element);用指定元素替换列表中指定位置的元素。

    (4)查:get(index):返回列表中指定位置的元素。
    subList(from,to);返回列表中指定的from到to之间的部分视图。
    listIterator();返回此列表元素的列表迭代器(按适当顺序)
    int indexOf(obj):获取指定元素的位置。

    ListIterator();Iterator方法的子类接口

2.迭代器

    迭代器是List集合特有的。

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

    提供的三种方法:

    boolean hasNext():返回集合里的下一个元素。

    Object next():返回集合里下一个元素。

    void remove();删除集合里上一次next方法返回的元素。

三、set集合

    set集合不允许包含相同的元素。set判断两个对象是否相同是根据equals方法。如果两个对象用equals方法返回的是true,set不会接受这两个对象。

    HashSet是set接口的典型实现,HashSet按hash算法来存储集合中的元素。因此具有很好的存储和查找性能。HashSet判断两个元素的标准是两个元素的equals方法比较相等,同时两个对象的hasCode()方法返回值也相等。HashSet可以保存null元素。

    TreeSet可对Set集合进行排序,依据是compareTo方法return 0。,当元素自身具有比较性时,通过实现compareTo接口,覆盖compareTo方法来完成排序。当元素自身不具备比较性时,或者具备的比较性不是所需要的,就需要让元素或者容器自身具有比较性。这时就要定义比较器。定义比较器后,将比较器对象作为参数传递给TreeSet集合的构造函数。当两种排序方式都存在时,以比较器为主。示例:

<span style="font-family:SimSun;font-size:12px;">import java.util.*;  //该接口强制让学生Student具备比较性。  class Student implements Comparable{  private String name;  private int age;  Student(String name,int age){          this.name = name;          this.age = age;  }  //复写Object类中hashCode方法  public int hashCode(){         //返回哈希值          return name.hashCode()+age*30;      }        //复写Object类中compareTo方法  public int compareTo(Object obj){          //如果obj对象不是Student类的实例          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;      }  }    class TreeSetDemo{  public static void main(String[] args){  TreeSet ts =new TreeSet();  ts.add(new Student("name01",21));  ts.add(new Student("name02",22));  ts.add(new Student("name06",26));  ts.add(new Student("name02",22));    Iterator it = ts.iterator();  while(it.hasNext()){              Student stu = (Student)it.next();              System.out.println(stu.getName()+"..."+stu.getAge());          }  }  } </span>

四、泛型

    泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。

1.好处

    (1)将运行时期出现问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时问题减少。

    (2)避免了强制转换麻烦。

2.泛型格式

    通过<>来定义要操作的引用数据类型。

    如:类:class Utils<类型未知,自定义>

       主函数中:Utils<类型未知,自定义> d = new Utils<类型未知,自定义>();

3.在使用java提供的对象时,什么时候写泛型呢?

    通常在集合框架中很常见,只要见到<>就要定义泛型,其实<> 就是用来接收类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

4.什么时候定义泛型类?

    当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型来完成扩展。

5.泛型定义在方法上

    泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

    为了让不同方法可以操作不同类型,而且类型还不确定,可以将泛型定义在方法上。

    特殊之处:静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

6.泛型定义在接口上

    将类型参数通过<>定义在interface关键字和{ 之间,这样这个接口就被声明成了泛型接口。如:class InterImpl<T> interface Inter<T>{}

    当接口的实现类可以确定实现的泛型接口上定义的类型参数的时候,就在implements关键字、接口的名字后面的<>中填写上具体的参数类型来替换接口中定义的类型参数。

    实现这个接口中的参数列表中含有类型参数构成的方法的时候,就直接使用实现类中在接口名称后面<>中声明的具体参数类型来替代接口中原有方法的参数列表中类型参数的部分即可。

7.通配符

    通配符,也可以理解为占位符,用“?”表示。

    泛型的限定:

    ? extends E: 可以接收E类型或者E的子类型。上限。

    ? super E: 可以接收E类型或者E的父类型。下限

五、Map集合

    Map集合用于保存具有映射关系的数据。Map接口有如下几个常用的实现类:HashMap、HashTable、TreeMap。TreeMap是基于二叉树对TreeMap中所有key进行排序。HashMap和HashTable主要区别有两点:1、Hashtable是线性安全的,因此性能差些。2、HashMap可以使用null作为key或者value。

1.Map集合特点

    该集合存储键值对,一对一对往里存,每个键最多只能映射到一个值。而且要保证键的唯一性。

2.Map的方法

   (1)添加

        put(K key, V value);将指定的值与此映射中的指定键关联

        putAll(Map<? extends K,? extends V> m); 

    (2)删除

        clear() 从此映射中移除所有映射关系

        remove(Object key)如果存在一个键的映射关系,则将其从此映射中移除

     (3)判断

        containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true

        containsKey(Object key)如果此映射包含指定键的映射关系,则返回 true

        isEmpty() 如果此映射未包含键-值映射关系,则返回 true

     (4)获取

        get(Object key)返回指定的键对应的值,如果此键不存在,则返回null

        size() 返回此映射中的键-值映射关系数。

        values() 返回此映射中包含的值的 Collection 视图

        entrySet() 返回此映射中包含的映射关系的 Set 视图

        keySet() 返回此映射中包含的键的 Set 视图。

注意:添加元素时如果出现相同的键,那么后添加的值会覆盖原有键的对应值,并且put方法会返回被覆盖的值。

      可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。

3.Map集合的两种取出方式

    (1)Set<k> keySet:将map中所有的键存入到Set集合,因为set具备迭代器。

               通过迭代方式取出所有的键,再根据get方法获取每一个键对应的值。

              取出原理:将map集合转成set集合,再通过迭代器取出。

    (2)Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是Map.Entry。

                                       Entry其实就是Map中的一个static内部接口。Map.Entry获取到后,就可以通过Map.Entry中getKey和getValue方法获取关系中的键值对。

                                       1)为什么要定义在内部呢?

                                         因为只有有了Map集合,有了键值对,才会有键值的映射关系。关系属于Map集合中的一个内部事物,而且该事物在直接访问Map集合中的元素。

4.set、list、map三者之间的关系:

    Set与Map的关系:。Map集合中所有key集中起来,就组成了一个set集合。所以Map集合提供Set<K> keySet()方法返回所有key组成的set集合。由此可见,Map集合中的所有key具有set集合的特征,只要Map所有的key集中起来,它就是一个Set集合,这就实现了Map到Set的转换。同时,如果把Map中的元素看成key-value的set集合,也可以实现从Set到Map之间的转换。HashSet和HashMap分别作为它们的实现类。两者之间也挺相似的。HashSet的实现就是封装了HashMap对象来存储元素。它们的本质是一样的。类似于HashSet和HashMap的关系,其实TreeMap和TreeSet本质也差不多,TreeSet底层也是依赖TreeMap实现。

    Map与List的关系:把Map的key-value分开来看,从另一个角度看,就可以把Map与List统一起来。Map集合是一个关联数组,key可以组成Set集合,Map中的value可以重复,所以这些value可以组成一个List集合。但是需要注意的是,实质Map的values方法并未返回一个List集合。而是返回一个不存储元素的Collection集合,换一种角度来看对List集合,它也包含了两组值,其中一组就是虚拟的int类型的索引,另一组就是list集合元素,从这个意思上看,List就相当于所有key都是int型的Map。

原创粉丝点击