黑马程序员_java集合框架(java collection framework)

来源:互联网 发布:华为mate9数据恢复 编辑:程序博客网 时间:2024/06/06 01:49
------- android培训、java培训、期待与您交流! ----------

java集合框架(java collection framework)

一、java集合的定义:

把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合。如一个国家、一个家庭、一个班级,一个团队,又如一堆东西、一群白马、一堆书等等。它们都是集合,是不同的个体所组成的。

二、集合的用处:

集合论是现代数学中重要的基础理论。它的概念和方法已经渗透到代数、拓扑和分析等许多数学分支以及物理学和质点力学等一些自然科学部门,为这些学科提供了奠基的方法,改变了这些学科的面貌。计算机科学作为一门现代科学因其与数学的缘源,自然其中的许多概念也来自数学,集合是其中之一。如果说集合论的产生给数学注入了新的生机与活力,那么计算机科学中的集合概念给程序员的生活也注入了新的生机与活力。

1.     它减少了程序设计的辛劳

集合框架通过提供有用的数据结构和算法使你能集中注意力于你的程序的重要部分上,而不是为了让程序能正常运转而将注意力于低层设计上。通过这些在无关API之间的简易的互用性,使你免除了为改编对象或转换代码以便联合这些API而去写大量的代码。

2.     它提高了程序速度和质量

集合框架通过提供对有用的数据结构和算法的高性能和高质量的实现使你的程序速度和质量得到提高。因为每个接口的实现是可互换的,所以你的程序可以很容易的通过改变一个实现而进行调整。另外,你将可以从写你自己的数据结构的苦差事中解脱出来,从而有更多时间关注于程序其它部分的质量和性能。

3.     减少去学习和使用新的API 的辛劳

许多API天生的有对集合的存储和获取。在过去,这样的API都有一些子API帮助操纵它的集合内容,因此在那些特殊的子API之间就会缺乏一致性,你也不得不从零开始学习,并且在使用时也很容易犯错。而标准集合框架接口的出现使这个问题迎刃而解。

4.     减少了设计新API的努力

设计者和实现者不用再在每次创建一种依赖于集合内容的API时重新设计,他们只要使用标准集合框架的接口即可。

5.     集合框架鼓励软件的复用

对于遵照标准集合框架接口的新的数据结构天生即是可复用的。同样对于操作一个实现了这些接口的对象的算法也是如此。

有了这些优点,并通过合理的使用,它就会成为程序员的一种强大的工具。不过,从历史上来看,集合大多其结构相当复杂,也就给它们一个造成极不合理的学习曲线的坏名声。但是,希望Java2的集合框架能缩短你的学习曲线,从而快速掌握它。

在许多高级语言中的数组其实也是集合的一种简单实现,比如C,C++,Pascal和Java。数组保存着相同类型的多个值,它的长度在数组被创建时就固定下来,建立之后就无法改变。如果你需要一种大小能动态改变的存储结构,数组就不适合了,这时集合框架就有了用武之地了。

三、java集合框架:

java集合框架分为两大类,分别是:CollectionMapCollection是单列集合,Map是双列集合。CollectionMap分别是这个两接口集合的根类集合。这两个接口下有自已的子接口和实现类。如图:

一、Collection集合的特点

Collection接口下有许多实现类和子接口,其中最常用到的list接口和Set接口以及一个抽象类AbstractList,在此抽象类中还有许多子类,常用的vector,ArrayList,AbstractSequentialList(抽象的,其下常用的LinkedList)HashSet,TreeSet,LinkedHashSet。此接口是单列集合。

List:其元素可以重复,即有多个相等的元素;List集合是有存放的自然顺序;可以像数组一样使用角标操作元素。

1)    Vectorjdk1.0的集合类,是线程安全的,它的内部数据结构为数组,其容量大小根据数据的的变化而调整其容量大小。jdk1.2后,此类改为实现了List接口。此类对数据的查询,取出速度快。对于数据的添加,插入效力不高,因为其在添加或插入数据时,还要去维护基角标。

2)    ArrayList是在jdk1.2后增加的集合,是线程不安全的,他的内部数据结构为数组,其容量根据数据的变化而调整其容量大小。注意!此类除了线程不安全以外,其他的Vector一样的。此类对数据的查询,取出速度快。对于数据的添加,插入效力不高,因为其在添加或插入数据时,还要去维护基角标。相对于Vector来说,基查询和取出速度要高效一些。

3)    linkedListjdk 1.2后增加的集合,是线程不安全的,其内部数据结构为链表列表结构。每个链节点中记录着上一个元素和下一个元素的地址。当需要插入数据时,只需记录上一个节点和下一个节点就行了。因此linkedList对于数据的添加和删除以及插入是高效力的。而相返,对数据的查询和取出是不高效的。因为其需要对每个节点进行编历,可可以到到相应的数据,所以效力不高。

Set:基元素不可以重复,即不有相等的元素存在;Set集合是没有存放的自然顺序;不可以像数组一样使用角标操作元素,对元素的操作是通过迭代器来操作元素。Set判断元素不相等的依据是hashcode()equals()法的返回值。因此在保存对像时,一般都会复写对象的hashcode()equals()方法。当hashcode()返回的值是相同的,但是equals返回的值不相同,那么这两对象视为不同的对像,相返的,如果hashcode()返回的哈希值不相等,那就没必要再执行equals(),直接视为两个不同的对像;只有两个对象的hashcode()equals()的返回值一样时,才视为同一个对象,此时,被添加的对象不会成功添加。

1)   HashSet jdk 1.2后增加的集合类,此类实现了Set接口,内部数据结构为哈希表;此类是线程不安全的;其存放位置由hash值确定。不能添加得重复的元素,即使添加了,也不会添加成功,也不会抛出异常。可以存储null作为值。当向一个HashSet添加元素时,HashSet集合会调用元素的hashcode()反回的哈希值与已存在的元素的哈希值进行比较,如果不同,就根据哈希值把元素添加到集合对应的哈希值位置中,添加成功;如果相同,再调用元素的equals()方法,返回结果再与已存在的元素equals返回值再比较,如果相同则视为同一个对象,添加不成功,如果不周,视为不同的对象元素,就根据哈希值把元素添加到集合对应的哈希值位置中,添加成功。当从HashSet中取一个元素时,首先计算该对象的哈希值,然后再根据哈希值到集合中对应的位置去取元素,如果返回来的哈希值相等,那么再调用该对像的equals()返回的值,根据返回值再取出正确的元素。

2)   TreeSet jdk 1.2增加的集合类,此类实现了Set接口,并实现了SortedSet接口;内部数据结构是地二叉树。线程不安全的。可以自定义顺序。添加到集合中的元素必须实现Comparable接口或在产生TteeSet时,在构造函数中,传入实现了Comparator接口的类的对象,基中实现的ComparableComparetoObject obj1)或ComparatorCompare(Object obj1,Object obj2)是我们实现自定义顺序的地方,所有的排序算法都在这里实现。ComparetoObject obj1)返回此对象为负整数,零,正整数分别小于,等于,大于指定对象。Compare(Object obj1,Object obj2)返回obj1为负整数,零,正整数分别小于,等于,大于obj2对象。假如集合为:{10,33,20,60,80,90,120,50}存到比较器为升序的TreeSet集合中时,如下图:

前序排序后为:{10203050608090120}

1)   LinkedHashSet jkd1.4增加的集合类,其数据结构为哈希链表结构。具有可预知迭代顺序,即可以以放入的顺序进行迭代取出元素。线程不安全。可以存储null值。与HashSet一样,它可以为基本操作(addcontainsremove)提供稳定的性能,假定哈希函数将元素正确地分布到存储段中。由于增加了维护链接列表的开支,其性能很可能会比HashSet稍逊一筹,不过,这一点例外:LinkedHashSet迭代所需时间与 set 大小成正比,而与容量无关。HashSet迭代很可能支出较大,因为它所需迭代时间与其容量成正比

一、Map集合的特点。

Map接口下有许多实现类和子接口,常用的接实现类:HashTableHashMapTreeMapLinkedHashMap.它们都是双列集合,就是以键值对集合。不可以有重复的键,可以有重复的值,null可以做为键或值存在。

1)  HashTablejdk 1.0以就有的双列Map集合,在jdk 1.2以后,改为实现Map接口,其数据结构是哈希表,线程安全的集合,以哈希值的形式存储。存进HastTable的元素必须实现hashcode()equals()方法。任何非null的元素都可以用为HashTable的键或值。

2)  HashMap jdk1.2增加的Map双列集合。其线程是不安全的,其数据结构是哈希表。除了线程不是同步的外,其他的和HashTable是一样的,在性能方面比HashTable高效,因为其没有同步的开销。所以效力上略高点。添加和删除都依赖于元素的hashcode()equals()方法。

3)  TreeMap jdk1.2增加的Map集合。其线程是不安全的,其数据桔构为二叉树。元素存放顺序是有比较器解定的。添加到TreeMap集合中的元素必需实现Comparable接口或在创建TreeMap集合时,在构造函数中指定实现了Comparator的类的对象。否则运行时,会报NullPointerException异常。如果试图装已存在的key添加到集合中,那么对应key的的值就会被修改。

4)  LinkedHashMap jdk 1.4增加的集合类,是双列集合,其线程是不安全的,其数据结构为哈希链表结构,具有可预知的迭代顺序。此实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序

二、何时使用集合。

怎样才能把集合用好呢,那就得从各种集合的特征出发,结合现实开发而要,巧妙地选择恰当的集合,将会使我们的开发更加容易。Java按其特征分为两大类,一类为单列集合,别一类为双列集合。单列集合以分为可重复的和不可重复的。双列集合就是键(key)和值(value)的映射关系,一个键对应一个值,都是成对出现,其中key不能重复。

1、  单列集合(Collection

1.1、        集合元素重复,有序(list)。

|--Vector:线程同步,元素查取速度快,新增和插入速度慢,可以有重复元素,数据结构为数组,容量可变。

|--ArrayList:线程不同步,元素查取相对于Vector速度更快,新增和插入速度慢,以有重复元素,数据结构为数组,容量可变。

|--LinkedList:线程不同步,元素查取数速度慢,元素的新曾和插入速度快,元素可有重复。数据结构为链接列表。

1.2、        集合元素不重复,无序(Set)

|--HashSet:线程不同步,没有重复的元素,无存放的先后顺序,数据结构为哈希表,元素需重写hashcode()equals()

|--TreeSet:线程不同步,没有重复的元素,存放顺序应自定义实现而定,数据结构为二叉树,元素需要实现ComparableComparator接口。

|--LinkedHashSet:线程不同步,没有重复元素,有着存放的先后顺序,数据结构为哈希和链接列表。元素需重写hashcode()equals()

2、  双列集合

|--Hashtble:线程同步,不能使用null作为键和值,无存放的先后顺序,数据结构为哈希表结构,重写hashcode()equals(),键值映射关系,

|--HashMap:线程不同步,可以使用null作为键和值,无存放的先后顺序,数据结构为哈希表结构。速度相对Hashtable要快,重写hashcode()equals(),键值映射关系。

|--TreeMap:线程不同步,可以使用null作为键和值,存放顺序应自定义实现而定,元素需要实现ComparableComparator接口。数据结构为二叉树,键值映射关系。

|--LinkedHashMap:线程不同步,可以使用null作为键和值,没有重复元素,有着存放的先后顺序,数据结构为哈希和链接列表。元素需重写hashcode()equals()

根据上述的集合的特征,我们在不同的场合中,根据需要选反恰当的集合类。如

1、  首先要确定我们的需求是单列还是双列,也就是说列表结构的数据,还是映射关系结构的数据,如果是列表结构,就选择单列(Collection)否则如果是映射关系的数据结构,即键值对关系,就选择双列(Map)。

2、  当我们选择单列时,再来分析我们的集合数据是否有重复,如果有,选择List体系,否则选择Set体系。

3、  当我们选择了List体系时,再分析我们的数据,如果多线程的话,我们可以直接使用Vector,也可以自已在外部加锁后,使用List体系的其他集合。如果是单线程,或没线程安全时,使用ArrayList

4、  当我们选择了List体系时,再分析我们的数据,如果需要有集合元素的先后顺序,如果多线程的话,我们可以直接使用Vector,也可以自已在外部加锁后,使用List体系的其他集合。如果是单线程,或没线程安全时,使用ArrayList

5、  当我们选择了List体系时,再分析我们的数据,如果平凡查取,如果多线程的话,我们可以直接使用Vector,也可以自已在外部加锁后,使用List体系的其他集合。如果是单线程,或没线程安全时,使用ArrayList。如果平凡新增、修改、插入的话,先择LinkedList

6、  我们选择了Set体系时,再分析我们的数据,如果数据不需要顺序的话,使用HashSet,否则如果数据需要顺序的话,使用TreeSetLinkedHashSet

7、  当我们选择了Map系系时,再来分析我们的数据结构,如果是多线程,可以选择Hashtable,也呆以加锁后,选择Map的其他休系,而如果是单线程的话,选择HashMap

8、  当我们选择了Map系系时,再来分析我们的数据结构,如果不需要存放顺序的话,如果是多线程,可以选择Hashtable,也呆以加锁后,选择Map的其他休系,而如果是单线程的话,选择HashMap,否则,选择TreeMapLinkedHashMap

三、集合的举例。

Vector的使用

package cn.javastudy.p1.Collection;

import java.util.*;

publicclass MyVector {

      publicstaticvoid main(String[] args)

      {

         Vector v=new Vector();

         v.add("张三");

         v.add("李四");

         v.add("王五");

         v.add("小六");

         Iterator it=v.iterator();

         while(it.hasNext())

            System.out.println(it.next());

      }

}

当在迭代中修改了集合的值,就会抛出ConcurrentModificationException,代码如下:

package cn.javastudy.p1.Collection;

import java.util.*;

publicclass MyVector {

   publicstaticvoid main(String[] args)

   {

      Vector v=newVector();

      v.add("张三");

      v.add("李四");

      v.add("王五");

      v.add("小六");

      Iterator it=v.iterator();

      while(it.hasNext())

      {

         String str=(String)it.next();

         System.out.println(str);

         v.add(str);

      }

   }

}

运行结果为:

张三

Exception in thread "main" java.util.ConcurrentModificationException

at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)

   at java.util.AbstractList$Itr.next(AbstractList.java:343)

   at cn.javastudy.p1.Collection.MyVector.main(MyVector.java:14)

原因为当在迭代器中,修改了集合时,就会发生此异常了。可以改为用ListIterator,代码如下:

package cn.javastudy.p1.Collection;

import java.util.*;

publicclass MyVector1 {

   publicstaticvoid main(String[] args)

   {

      Vector v=newVector();

      v.add("张三");

      v.add("李四");

      v.add("王五");

      v.add("小六");

      ListIterator it=v.listIterator();

      while(it.hasNext())

      {

         String str=(String)it.next();

         it.add(str);

         System.out.println(str);

         System.out.println(v);

      }

   }

}

ArrayList的使用:

package cn.javastudy.p2.Collection;

import java.awt.peer.SystemTrayPeer;

import java.util.*;

public class MyVector3 {

    public static void main(String[] args)

    {

       ArrayList<Integer> v=new ArrayList<Integer>();

       //向ArrayList中添加元素

       v.add(100);

       v.add(200);

       v.add(30);

       v.add(1);

       System.out.println("向集合中添加元素后:"+v);

       //向ArrayList中插入元素.

       v.add(2,3000);

       System.out.println("向集合中插入元素后:"+v);

       //修改ArrayList中的第三个元素

       v.set(3, 10000);

       System.out.println("改改索引为三的元素后:"+v);

       //删除集合中的第三个元素后

       v.remove(3);

       System.out.println("删除集合中的第三个元素后:"+v);

       //删除集合中的全部元素

       v.clear();

       System.out.println("清除合部元素后"+v);

    }

}

ArrayList迭代

package cn.javastudy.p2.Collection;

import java.awt.peer.SystemTrayPeer;

import java.util.*;

public class MyVector3 {

    public static void main(String[] args)

    {

       ArrayList<Integer> v=new ArrayList<Integer>();

       //向ArrayList中添加元素

       v.add(100);

       v.add(200);

       v.add(30);

       v.add(1);

       Iterator it=v.iterator();

       while(it.hasNext())

           System.out.println(it.next());

    }

}

LinkedList的使用:

package cn.javastudy.p3.Collection.copy;

import java.awt.peer.SystemTrayPeer;

import java.util.*;

@SuppressWarnings("unused")

public class MyVector3 {

    public static void main(String[] args)

    {

       LinkedList<Integer> v=new LinkedList<Integer>();

       //向LinkedList中添加元素

       v.add(100);

       v.add(200);

       v.add(30);

       v.add(1);

       Iterator it=v.iterator();

       //迭代

       while(it.hasNext())

           System.out.println(it.next());

    }

}

HashSet的使用

package cn.javastudy.p3.Collection.copy;

import java.awt.peer.SystemTrayPeer;

import java.util.*;

@SuppressWarnings("unused")

public class MyVector3 {

    public static void main(String[] args)

    {

       HashSet<myInteger> v=new HashSet<myInteger>();

       //向ArrayList中添加元素

       v.add(new myInteger(10));

       v.add(new myInteger(1100));

       v.add(new myInteger(20));

       v.add(new myInteger(50));

       Iterator<myInteger> it=v.iterator();

       while(it.hasNext())

           System.out.println(it.next().getIt());

       System.out.println(new myInteger(10).getIt());

    }

}

class myInteger

{

    Integer it=null;

 

    public Integer getIt() {

       return it;

    }

 

    public myInteger(Integer it) {

       super();

       this.it = it;

    }

 

    @Override

    public int hashCode() {

       final int prime = 31;

       int result = 1;

       result = prime * result + ((it == null) ? 0 : it.hashCode());

       return result;

    }

 

    @Override

    public boolean equals(Object obj) {

       if (this == obj)

           return true;

       if (obj == null)

           return false;

       if (getClass() != obj.getClass())

           return false;

       myInteger other = (myInteger) obj;

       if (it == null) {

           if (other.it != null)

               return false;

       } else if (!it.equals(other.it))

           return false;

       return true;

    }

}

TreeSet的应用。

package cn.javastudy.p3.Collection.copy;

import java.awt.peer.SystemTrayPeer;

import java.util.*;

@SuppressWarnings("unused")

public class MyVector3 {

    public static void main(String[] args)

    {

       MyComparator com=new MyComparator();

       TreeSet<myInteger> v=new TreeSet<myInteger>(com);

       //向ArrayList中添加元素

       v.add(new myInteger(10));

       v.add(new myInteger(40));

       v.add(new myInteger(20));

       v.add(new myInteger(50));

       v.add(new myInteger(50));

       Iterator<myInteger> it=v.iterator();

       while(it.hasNext())

           System.out.println(it.next().getIt());

    }

}

class myInteger extends abc

{

    public Integer getIt() {

       return it;

    }

    public myInteger(Integer it) {

       this.it = it;

    }

    public boolean equals(Object obj) {

       return it.equals(((myInteger)obj).it);

    }

   

   

}

class abc

{

    Integer it=null;

}

class MyComparator implements Comparator<abc>

{

 

    @Override

    public int compare(abc o1, abc o2) {

       if(o1.equals(o2))

           return 0;

       return o1.it<o2.it?-1:1;

    }

}

原创粉丝点击