【Java学习笔记】Java集合类总结

    xiaoxiao2021-03-25  62

     一集合  

        对JAVA的集合的理解是想对于数组,数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型)。JAVA集合可以存储和操作数目不固定的一组数据。JAVA集合只能存放引用类型的的数据,不能存放基本数据类型.所有的JAVA集合都位于 java.util包中!

         世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合   有人想有可以自动扩展的数组,所以有了List   有的人想有没有重复的数组,所以有了set   有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree**      而几乎有有的集合都是基于数组来实现的.   因为集合是对数组做的封装,所以,数组永远比任何一个集合要快      但任何一个集合,比数组提供的功能要多      一:数组声明了它容纳的元素的类型,而集合不声明。这是由于集合以object形式来存储它们的元素。      二:一个数组实例具有固定的大小,不能伸缩。集合则可根据需要动态改变大小。      三:数组是一种可读/可写数据结构---没有办法创建一个只读数组。然而可以使用集合提供的ReadOnly方法,以只读方式来使用集合。该方法将返回一个集合的只读版本。 四:

    array还有一个缺点是,无法判断其中实际存有多少元素,length只是告诉我们array的容量。

        JAVA集合主要分为三种类型:  Set 和List 都继承了Conllection,Map没有     Set(集)     List(列表)     Map(映射)

        

    Collection 接口

        Collection是最基本的集合接口,声明了适用于JAVA集合(只包括Set和List)的通用方法。

        Collection接口的方法:     boolean add(Object o)   :向集合中加入一个对象的引用     void clear()                        :删除集合中所有的对象,即不再持有这些对象的引用     boolean isEmpty()           :判断集合是否为空     boolean contains(Object o): 判断集合中是否持有特定对象的引用     Iterartor iterator()              : 返回一个Iterator对象,可以用来遍历集合中的元素     boolean remove(Object o):从集合中删除一个对象的引用     int size()                               :返回集合中元素的数目     Object[] toArray()                 :返回一个数组,该数组中包括集合中的所有元素     关于:Iterator() 和toArray() 方法都用于集合的所有的元素,前者返回一个Iterator对象,后者返回一个包含集合中所有元素的数组。     Iterator接口声明了如下方法:     hasNext(): 判断集合中元素是否遍历完毕,如果没有,就返回true     next()       :返回下一个元素     remove():从集合中删除上一个有next()方法返回的元素。

    二 Set

    Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。

    Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。

    Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。 Set接口主要实现了三个实现类:HashSet,linkedHashSet TreeSet    

    HashSet

    Set的实现类HashSet,底层还是调用Map接口来处理。HashSet有以下特点  不能保证元素的排列顺序,顺序有可能发生变化  不是同步的  集合元素可以是null,但只能放入一个null 当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。 简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等 注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

    LinkedHashSet LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。 LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

    TreeSet类 TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。 TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0 自然排序 自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。 Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。 obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。 如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0 定制排序 自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法

    下面看一个具体的例子:

    package com.test; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.TreeSet; /** * @description 几个set的比较 * HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放; * LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代; * TreeSet:提供一个使用树结构存储Set接口的实现,对象以升序顺序存储,访问和遍历的时间很快。 * @author Zhou-Jingxian * */ public class SetDemo { public static void main(String[] args) { HashSet hs = new HashSet (); hs.add("B"); hs.add("A"); hs.add("D"); hs.add("E"); hs.add("C"); hs.add("F"); System.out.println("HashSet 顺序:\n"+hs); LinkedHashSet lhs = new LinkedHashSet (); lhs.add("B"); lhs.add("A"); lhs.add("D"); lhs.add("E"); lhs.add("C"); lhs.add("F"); System.out.println("LinkedHashSet 顺序:\n"+lhs); TreeSet ts = new TreeSet (); ts.add("B"); ts.add("A"); ts.add("D"); ts.add("E"); ts.add("C"); ts.add("F"); System.out.println("TreeSet 顺序:\n"+ts); } } 输出结果为:

    HashSet 顺序:[D, E, F, A, B, C] LinkedHashSet 顺序:[B, A, D, E, C, F]TreeSet 顺序:[A, B, C, D, E, F]

    三 列表

    列表的主要特征是其对象以线性方式存储,没有特定顺序,只有一个开头和一个结尾,当然,它与根本没有顺序的集是不同的

    列表在数据结构中分别表现为:list和向量、堆栈、队列。

    List : 次序是List最重要的特点:它保证维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(这只推荐LinkedList使用。)一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和移除元素。实际上有两种List: 一种是基本的ArrayList,其优点在于随机访问元素,另一种是更强大的LinkedList,它并不是为快速随机访问设计的,但是插入与删除的开销不大。

        ArrayList : 实现了基于动态数组的数据结构。允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和移除元素。因为那比LinkedList开销要大很多。对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针     LinkedList : 基于双向循环链表的数据结构,对顺序访问进行了优化,向List中间插入与删除的开销并不大。随机访问则相对较慢。(使用ArrayList代替。)还具有下列方法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 这些方法 (没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据

    List接口提供的适合于自身的常用方法均与索引有关,这是因为List集合为列表类型,以线性方式存储对象,可以通过对象的索引操作对象。 List接口的常用实现类有ArrayListLinkedList,在使用List集合时,通常情况下声明为List类型,实例化时根据实际情况的需要,实例化为ArrayListLinkedList,例如: List<String> l = new ArrayList<String>();// 利用ArrayList类实例化List集合 List<String> l2 = new LinkedList<String>();// 利用LinkedList类实例化List集合

      最基本的两种检索集合中的所有对象的方法:     1: 用for循环和get()方法:     for(int i=0; i<list.size();i++){     System.out.println(list.get(i));     }     2: 使用 迭代器(Iterator):     Iterator it=list.iterator();     while(it.hashNext){     System.out.println(it.next);     }

    Vector: Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。vector实现一个类似数组一样的表,自动增加容量来容纳你所需的元素。使用下标存储和检索对象就象在一个标准的数组中一样。你也可以用一个迭代器从一个Vector中检索对象。Vector是唯一的同步容器类!!当两个或多个线程同时访问时也是性能良好的。

    关于ArrayList和Vector区别如下:

    ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。Vector提供indexOf(obj, start)接口,ArrayList没有。Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。

    Stsck: 这个类从Vector派生而来,并且增加了方法实现栈!一种后进先出的存储结构。

     四。map

        Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。

        Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。 Map集合中的键对象不允许重复,也就说,任意两个键对象通过equals()方法比较的结果都是false.但是可以将任意多个键独享映射到同一个值对象上。     Map 的常用方法:     1 添加,删除操作:     Object put(Object key, Object value): 向集合中加入元素     Object remove(Object key):   删除与KEY相关的元素     void putAll(Map t):   将来自特定映像的所有元素添加给该映像     void clear(): 从映像中删除所有映射     2 查询操作:     Object get(Object key): 获得与关键字key相关的值    

    方法put(Object key, Object value)添加一个“值”(想要得东西)和与“值”相关联的“键”(key)(使用它来查找)。方法get(Object key)返回与给定“键”相关联的“值”。可以用containsKey()和containsValue()测试Map中是否包含某个“键”或“值”。 标准的Java类库中包含了几种不同的Map:HashMap, TreeMap, LinkedHashMap, WeakHashMap, IdentityHashMap。它们都有同样的基本接口Map,但是行为、效率、排序策略、保存对象的生命周期和判定“键”等价的策略等各不相同。 

    HashTable: 实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承,并且通常能在实现映象的其他类中更好的使用。

    HashMap:实现一个映象,允许存储空对象,而且允许键是空(由于键必须是唯一的,当然只能有一个)。Map基于散列表的实现。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因子load factor,以调整容器的性能。 

    LinkedHashMap: 类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。 

    TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特点在 于,你得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。 

    WeakHashMao :弱键(weak key)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。 

    IdentifyHashMap: : 使用==代替equals()对“键”作比较的hash map。专为解决特殊问题而设计。

    下面是一个hash map的例子:

    package com.xtfggef.map.test; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * HashMap的使用 * @author erqing * */ public class MapTest { public static void main(String[] args) { /* 初始化map */ Map map = new HashMap (); System.out.println("HashMap的初始值:" + map.size()); System.out.println("HashMap是否为空:" + (map.isEmpty() ? "是" : "否")); /* 想map中添加元素 */ map.put("erqing", 1); map.put("niuniu", 2); map.put("egg", 3); System.out.println(map.size()); ; System.out.println("HashMap是否为空:" + (map.isEmpty() ? "是" : "否")); /* 遍历HashMap中的元素 */ Set set = map.keySet(); for (String s : set) { System.out.println(s + " " + map.get(s) + " " + "hashcode:" + s.hashCode()); } /*检测是否含有某个Key*/ System.out.println(map.containsKey("egg")); /*检测是否含有某个Value*/ System.out.println(map.containsValue(2)); /*打印hashCode*/ System.out.println(map.hashCode()); } } 输出:

    HashMap的初始值:0        HashMap是否为空:是        3        HashMap是否为空:否        niuniu 2 hashcode:-1045196352        egg 3 hashcode:100357        erqing 1 hashcode:-1294670850        true        true       1955200455

    此处附一个利用HashMap来简单处理问题的例子,需求在注释中已经给出,希望读者好好看看,代码不难,但是很多的面试及面试题都用到这个思路,笔者曾经面试的时候,经常会被问题这题的思想,但是就是没有去亲自实现一下,以致在hashmap的操作上被难住了。

    package com.xtfggef.hashmap; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * 打印在数组中出现n/2以上的元素 * 利用一个HashMap来存放数组元素及出现的次数 * @author erqing * */ public class HashMapTest { public static void main(String[] args) { int [] a = {2,3,2,2,1,4,2,2,2,7,9,6,2,2,3,1,0}; Map map = new HashMap (); for(int i=0; i set = map.keySet(); for (Integer s : set) { if(map.get(s)>=a.length/2){ System.out.println(s); } } } }

    五。总结

    1. 如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。 2. 如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。 3. 在除需要排序时使用TreeSet,TreeMap外,都应使用HashSet,HashMap,因为他们 的效率更高。 4. 要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。 5. 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。一旦将对象置入容器内,便损失了该对象的型别信息。 6. 尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

    7.Collection、List、Set、Map都是abstract接口,不能实例化。继承自它们的 ArrayList, Vector, HashTable, HashMap是具象class,这些才可被实例化。

    8.vector容器确切知道它所持有的对象隶属什么型别。vector不进行边界检查

    部分内容整理自网络。

    reference:

    http://blog.csdn.net/zhangerqing/article/details/8122075

    http://www.cnblogs.com/eflylab/archive/2007/01/19/625086.html

    http://blog.csdn.net/lushuaiyin/article/details/7381478/

    http://blog.csdn.net/speedme/article/details/22398395

    http://www.cnblogs.com/wanlipeng/archive/2010/10/21/1857791.html

      
    转载请注明原文地址: https://ju.6miu.com/read-34292.html

    最新回复(0)