`

从提高存取效率的角度深入“集合框架”

阅读更多

 

 

在开始之前,我先提出问题引出整片的论述:

    问题:1、我们已经知道JDK提供的集合有很多种,我们应该通过哪些标准(比如执行效率等)来选取合适的集合使用?

             2、各种集合之间的关系到底是怎样的?

             3、各种集合的适用情况如何,即如何选取才能使你的程序的效率最高?

 下面,我就来试图解决这些问题!

 

一、基于图的集合框架整体认知

 


 

接口关系图详解:

 

 

更加详细的框架图见:http://hi.baidu.com/%C9%AE_%CC%C6/blog/item/9e2a8b0887008a8ad0581b3d.html

 

 

二、部分接口或类的分析

 

1、整个框架主要包括三大接口:

 

   java.util.Set 接口及其子类,set提供的是一个无序的集合。

   java.util.List 接口及其子类,List提供的是一个有序的集合

   java.util.Map 接口及其子类,Map提供了一个映射(对应)关系的结合数据结构。

   另外,在JDK5中新增了Queue(队列)接口及其子类,提供了基于队列的集合框架。并且,我们应该没有忘记自己最初是通过自定义数组和自定义队列来实现对象的集合存储的。

 

 

2、遍历问题:

 

   Collection类的遍历使用iterator()方法。所以,所有实现它的类都可以使用这个方法来达到遍历。

   List提供了一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加、删除、设定元素,还能向前向后遍历。可以说ListIteratorIterator的升级版。

   遍历HashMap

 

            方法一:  用entrySet()

           Iterator it=map.entrySet().iterator();

           while(it.hasNext()){

                Map.Entry entry=(Map.Entry)it.next(); 

           }

 

            方法二:应用for-Each+keySet()循环:

            for(Object o:map.keySet){

                    Value value=map.get(o);

             }

 

             方法三:用entrySet()or-Each循环

           for(Map.Entry<> m:map.entrySet()){

                 //m是映射项

            }

                    本方法同for(Map.Entry<> m:map){}(不过前提是所有的<>中类型都要指定)

 

            方法四:用keySet()

            Iterator it=map.keySet().iterator();

           while(it.hasNext()){

                String key=(keyType)it.next();

                Value value=map.get(key); 

           }

 

方法一比方法四效率高,因为对keySet其实是遍历了两次,一次是转为iterator,一次就是取出key对应的value,而entrySet只遍历了一次。

 

    

3、接口及其实现类(本条相关论述详见JDK文档):本条的论述主要涉及同步问题方法的时间开销容量等问题。

 

   Collection接口:允许参数为Collection的构造器,实际上就是实现用户复制一个Collection

   

     SortedSet<E>接口:继承自Set接口,使用自然顺序进行排序,或者在创建有序set是提供的Comparator进行排序。该set的迭代器将元素升序遍历set

   

   HashSet<E>应用HashMap的一个集的实现。固然集定义成无序,但必须存在某种方法能相当高效地找到一个对象。应用一个HashMap对象实现集的存储和检索把持是在固定时间内实现的.   

 

 

    LinkedList:提供了getremoveinsert的额外的方法,实现在LinkedList首部或尾部作用。这些操作时LinkedList可悲用作堆栈(Stack)、队列(queue)、或双向队列(deque)

    注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:  
  List  list  =  Collections.synchronizedList(new  LinkedList(...));   

 

 

    ArrayListsizeisEmptygetset方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。 

当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList容量以提高插入效率。  

 同样,该类unsynchronized

 

     Vector:实现了List接口。synchronized。当一个Interator被创建而且正在被使用,另一个线改变了Vector的状态,这是调用Iterator的方法将抛出ConcurrentModificationException 

 

    

         Stack继承自Vector,实现一个后进先出的堆栈。 

 

    

    Map接口Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。   

 

 

     HashMapunsynchronized。允许null,即null vlauenull key但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load  factor过低。   

 

    

          Hashtable 由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCodeequals方法hashCodeequals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。  

  如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。 

 

 

 

 本条小结HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。 如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。 

 

 

参考:http://dev.firnow.com/course/3_program/java/javajs/2007917/71621.html 

             

          

   

三、扩展

 

1、散列表(也叫哈希表):从哈希表的优势入手


    数据结构中,有个时间算法复杂度O(n)的概念来衡量某种算法在时间效率上的优劣。哈希表的理想算法复杂度为O(1),也就是说利用哈希表查找某个值,系统所使用的时间在理想情况下为定值,这就是它的优势。那么哈希表是如何做到这一点的呢?
    实际生活中有这样一个mapping需要存储:name-value。存储和读取整个流程为:

    A、开辟一块空间(HashValues[m])用于存储value;

B、通过哈希函数(ChangeToHashValue (name))计算出name的哈希码hashcode(name)=x.

C、将value存储到hachValues[x]中。到这里存储就完毕了。

D、读取时,给定name,通过哈希函数(ChangeToHashValue (name))计算出哈码hashcode(name)=x

E、读取HashValue [x]

 

不过,实际上m总是大于实际需要的n的,所以这其实是用空间换时间的数据结构。

 

不过,哈希表的方法也会遇到问题

当两个不同的name值经过哈希函数的计算结构得到的哈希值相同,那么就会出现冲突。冲突使得哈希表的存取速度变慢。解决方法有两种:一种就是定义一个好的哈希函数;另一种就是在不改变哈希函数的情况下用后续的手段解决冲突,如出现重复hashcode1等等。

 

 

2、HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素 

 

   当我们试图把某个类的对象当成 HashMap 的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的 equals(Object obj) 方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。 

    // 根据 first 判断两个 Name 是否相等 

    public boolean equals(Object o)   

    {   

        if (this == o)   

        {   

            return true;   

        }   

        if (o.getClass() == Name.class)   

        {   

10             Name n = (Name)o;   

11             return n.first.equals(first);   

12         }   

13         return false;   

14     }   

15        

16     // 根据 first 计算 Name 对象的 hashCode() 返回值  

17     public int hashCode()   

18     {   

19         return first.hashCode();   

20     }  

 

四、最后的总结:

 

1、集合框架中各个类的使用需要考虑空间占用率(容量,通过loadFactor 属性来设置)、同步问题、是否可以存入null值、各种类的区别与选择、遍历选择等问题。这些问题,在我上面的论述中多多少少有涉及,其中各个类的区别、是否存入null值、同步问题、以及部分类空间占用等问题我只是做了一个引入式的分析,并没有分析到能应用的层面。这点是还可以进一步研究的地方。  

 

 

  • 大小: 66.6 KB
  • 大小: 58 KB
分享到:
评论

相关推荐

    集合框架的总结

    此外,`Stream API`自Java 8引入,为集合处理提供了函数式编程风格,支持并行操作,极大地提高了代码的简洁性和效率。 对于源码阅读,理解集合框架的实现细节至关重要。以`ArrayList`为例,其内部使用动态增长的...

    Java集合框架详解

    Java集合框架是Java编程语言中不可或缺的一部分,它提供了一种高效、灵活的方式来存储和操作数据。...此外,深入学习集合框架的源码,可以进一步理解其内部实现机制,有助于编写更高效、更优化的代码。

    数据结构和Java集合框架

    数据结构和Java集合框架是Java编程中至关重要的概念,它们是高效编程和算法设计的基础。在Java中,数据结构指的是组织、存储和管理数据的方式,而集合框架则是一组接口和类,为处理各种数据结构提供了统一的API。 ...

    9、JavaSE:集合框架.pdf

    集合框架的设计使得程序员在处理数据集合时可以更加高效和方便,无论是在空间的利用还是数据的存取方面。 首先,集合框架解决了程序员在不知道程序运行时需要多少对象,或者对象存储方式更复杂时的困扰。比如,如果...

    轻松学Java之集合框架优秀PPT.pptx

    本章我们将深入探讨Java集合框架,包括其概念、接口以及不同类型的集合结构。 首先,集合框架的概念是将一组具有相同属性的对象组织在一起的容器。它提供了一种抽象的方式来存储、检索、操作和传输数据,极大地提升...

    分布式数据库中数据存取效率管理仿真.pdf

    为了适应这一趋势,提高分布式数据库中数据存取的效率和准确性,需要不断探索新的算法和技术,如本文所提出的基于主成分分析的数据快速存取方法,便是其中之一。这类研究对于推动分布式数据库技术的发展和应用具有...

    基于Oracle空间数据库的源数据组织存取效率分析.pdf

    以点状和面状对象为例,展示了不同数据量下所需存储空间的计算方法,进一步分析了源数据大小和拓扑结构对存取速度的影响,并提出了优化源数据组织以提高空间数据库存取效率的策略。 【关键知识点】 1. Oracle空间...

    Java集合框架.pdf

    集合框架的目的是为了提供一套统一的集合操作方法,以降低编程时的复杂性,提高代码的可重用性。在Java集合框架中,所有的集合类都实现了Collection接口,而Map则是独立的接口。 Collection接口是集合框架中层次...

    java中容器类ArrayList(底层数组实现)和数组存取效率简单测试

    本篇文章将深入探讨ArrayList的工作原理,以及它与普通数组在存取效率上的差异。 ArrayList的核心是内部的数组对象,它在初始化时会创建一个默认大小(通常是10)的数组。当添加元素超过当前数组容量时,ArrayList...

    轻松学Java之集合框架.pptx

    理解并熟练掌握Java集合框架能够帮助开发者更有效地组织和操作数据,提高代码的可读性和可维护性。在编程实践中,应根据具体场景选择恰当的集合类型,合理利用其提供的方法,以实现高效的数据处理。同时,Java集合...

    java集合框架,泛化.doc

    Java集合框架是Java编程语言中一个非常核心的部分,它提供了一组高效且灵活的数据结构,如列表、集合、映射等,使得开发人员能够更好地管理和操作数据。泛型是Java集合框架的重要特性,它允许在定义集合类或者方法时...

    深入剖析java中的集合框架

    本文将深入剖析Java集合框架的核心概念、主要接口及其实现,并通过实例演示如何使用ArrayList集合类。 首先,Java集合框架的核心是提供了一种灵活的方式来存储和管理对象,弥补了传统数组在动态扩展和复杂数据结构...

    Java集合框架类学习啊

    在实际编程中,理解并熟练使用这些接口和实现类可以极大地提高代码的效率和可维护性。开发者可以根据具体需求选择合适的数据结构,比如需要保持元素顺序时使用List,需要保证元素唯一性时选择Set,或者需要通过键来...

    Java集合框架常见面试题夜间阅读版.pdf

    Java集合框架是Java编程语言中非常核心且重要的知识点,它广泛应用于数据的存储、处理与检索。Java集合框架主要包括Collection接口和Map接口两大体系。Collection接口下的主要类包括List、Set和Queue等,而Map接口则...

    JAVA集合框架

    JAVA集合框架是Java编程语言中一个至关重要的组件,它提供了一种高效且灵活的方式来存储和操作数据。集合框架由接口、抽象类和实现类组成,主要用于处理对象的集合,简化了数据管理。以下是对集合框架核心概念的详细...

    地震资料分布式存取的效率优化设计.pdf

    综上所述,本文针对传统地震资料存取方法的局限性,提出了一种基于Hadoop框架的分布式存取优化设计,通过混合索引查询方法和预处理技术,旨在在不增加成本的前提下提升数据存取效率,对于处理大规模非结构化数据具有...

    SharedPreferences存取list集合

    但通过一些技巧,我们可以实现将List集合存取到SharedPreferences中。下面我们将详细探讨如何实现这一功能。 首先,了解SharedPreferences的基本用法。SharedPreferences是Android提供的一个接口,用于存储和读取...

    智能存取系统对急诊药房工作效率的影响.pdf

    1. 提高药品配发速度:智能存取系统可以快速定位到药品的位置,并能即时分拣出需要的药品,极大缩短了从接到医生处方到配发药品的时间。 2. 减少药品管理错误:系统提供的精确药品管理与自动化的分拣功能,降低了因...

Global site tag (gtag.js) - Google Analytics