zoukankan      html  css  js  c++  java
  • Java-list,set,map的区别

    jdk中api的定义

    Collection
      ├----List
      │  ├----LinkedList
      │  ├----ArrayList
      │  └----Vector
      │     └----Stack
      └----Set


    Map
      ├----Hashtable
      ├----HashMap
      ├    ├----LinkedHashMap
      └----WeakHashMap

    Set,List,Map的区别

    java集合的主要分为三种类型:
    • Set(集)
    • List(列表)
    • Map(映射)
    要深入理解集合首先要了解下我们熟悉的数组:
      数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),而JAVA集合可以存储和操作数目不固定的一组数据。 所有的JAVA集合都位于 java.util包中! JAVA集合只能存放引用类型的的数据,不能存放基本数据类型。
    世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合  
    有人想有可以自动扩展的数组,所以有了List  
    有的人想有没有重复的数组,所以有了set  
    有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree**  
      
    而几乎有有的集合都是基于数组来实现的.  
    因为集合是对数组做的封装,所以,数组永远比任何一个集合要快  
      
    但任何一个集合,比数组提供的功能要多  
      
    一:数组声明了它容纳的元素的类型,而集合不声明。这是由于集合以object形式来存储它们的元素。  
      
    二:一个数组实例具有固定的大小,不能伸缩。集合则可根据需要动态改变大小。  
      
    三:数组是一种可读/可写数据结构---没有办法创建一个只读数组。然而可以使用集合提供的ReadOnly方法,以只读方式来使用集合。该方法将返回一个集合的只读版本。

     Collection接口

    public interface Collection<E> extends Iterable<E>

      Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)

       一些 Collection允许相同的元素而另一些不行。一些能排序而另一些不行。

       Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。

       所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个 Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个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()方法返回的元素。

     

    如何遍历Collection中的每一个元素?

      不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下: 

    Iterator it = collection.iterator(); // 获得一个迭代子
    while(it.hasNext()) {
      Object obj = it.next(); // 得到下一个元素
    }

     由Collection接口派生的两个接口是List和Set。

     List接口

    public interface List<E> extends Collection<E>

    List的特征是其元素以线性方式存储,集合中可以存放重复对象。 

    ArrayList() : 代表长度可以改变得数组。可以对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。 
    LinkedList(): 在实现中采用链表数据结构。插入和删除速度快,访问速度慢。 

       List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
    和下面要提到的Set不同,List允许有相同的元素。

      除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。

      实现List接口的常用类有LinkedListArrayListVectorStack

      对于List的随机访问来说,就是只随机来检索位于特定位置的元素。 List 的 get(int index) 方法放回集合中由参数index指定的索引位置的对象,下标从“0” 开始。最基本的两种检索集合中的所有对象的方法:  

     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());  
     
    }  

    次序是List最重要的特点:它保证维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(这只推 荐LinkedList使用。)一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和移除元 素。 

    LinkedList类

    public class LinkedList<E>
        extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable

      LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
      注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

        List list = Collections.synchronizedList(new LinkedList(...));

     对顺序访问进行了优化,向List中间插入与删除的开销并不大。随机访问则相对较慢。(使用ArrayList代替。)还具有下列方 法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 这些方法 (没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。

    ArrayList类

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable

      ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
    size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
      每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
      和LinkedList一样,ArrayList也是非同步的(unsynchronized)。

     由数组实现的List。允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历 ArrayList,而不是用来插入和移除元素。因为那比LinkedList开销要大很多。 

    Vector类

    public class Vector<E>
        extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

      Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

    Stack 类

    public
    class Stack<E> extends Vector<E> 

      Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

      stack后进先出的方式为通过pop()方法获取顶部对象,也就是最后一个添加的为顶部对象,然后将这个顶部对象从stack容器中删除,在使用pop时为stack容器的中元素前移

    import java.util.Stack;  
      
      
    public class StackTest {  
      
        public static void main(String[] args) {  
            Stack<String> stack = new Stack<String>();  
            System.out.println("now the stack is " + isEmpty(stack));  
            stack.push("1");  
            stack.push("2");  
            stack.push("3");  
            stack.push("4");  
            stack.push("5");  
            System.out.println("now the stack is " + isEmpty(stack));  
            System.out.println(stack.peek());  
            System.out.println(stack.pop());  
            System.out.println(stack.pop());  
            System.out.println(stack.search("2"));  
        }  
        public static String isEmpty(Stack<String> stack) {  
            return stack.empty() ? "empty" : "not empty";  
        }  
    }  

    输出

    now the stack is not empty  
    5  
    5  
    4  
    2  

    Set接口

    public interface Set<E> extends Collection<E> 

      Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素
      很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
      请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

      Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类: 

    HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 
    TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。 

    Set 的用法:存放的是对象的引用,没有重复对象

    Set set=new HashSet();   
    String s1=new String("hello");   
    String s2=s1;   
    String s3=new String("world");   
    set.add(s1);   
    set.add(s2);   
    set.add(s3);   
    System.out.println(set.size());//打印集合中对象的数目 为 2

    Set 的 add()方法是如何判断对象是否已经存放在集合中? 

    boolean isExists=false;  
    Iterator iterator=set.iterator();   
    while(it.hasNext()){   
      String oldStr=it.next();   
      if(newStr.equals(oldStr)){   
        isExists=true;   
      }   
    } 

    Set的功能方法 

    Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List。实际上Set就是Collection,只 是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素(至于如何判断元素相同则较为负责) 

    Set : 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 

    HashSet:为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。 
    TreeSet: 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。 
    LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

    HashSet

    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable

    其中方法:

    // 使用 HashMap 的 key 保存 HashSet 中所有元素  
     private transient HashMap<E,Object> map;   
     // 定义一个虚拟的 Object 对象作为 HashMap 的 value   
     private static final Object PRESENT = new Object();   
     ...   
     // 初始化 HashSet,底层会初始化一个 HashMap   
     public HashSet()   
     {   
         map = new HashMap<E,Object>();   
     }   
     // 以指定的 initialCapacity、loadFactor 创建 HashSet   
     // 其实就是以相应的参数创建 HashMap   
     public HashSet(int initialCapacity, float loadFactor)   
     {   
         map = new HashMap<E,Object>(initialCapacity, loadFactor);   
     }   
     public HashSet(int initialCapacity)   
     {   
         map = new HashMap<E,Object>(initialCapacity);   
     }   
     HashSet(int initialCapacity, float loadFactor, boolean dummy)   
     {   
         map = new LinkedHashMap<E,Object>(initialCapacity   
             , loadFactor);   
     }   
     // 调用 map 的 keySet 来返回所有的 key   
     public Iterator<E> iterator()   
     {   
         return map.keySet().iterator();   
     }   
     // 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数  
     public int size()   
     {   
         return map.size();   
     }   
     // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,  
     // 当 HashMap 为空时,对应的 HashSet 也为空  
     public boolean isEmpty()   
     {   
         return map.isEmpty();   
     }   
     // 调用 HashMap 的 containsKey 判断是否包含指定 key   
     //HashSet 的所有元素就是通过 HashMap 的 key 来保存的  
     public boolean contains(Object o)   
     {   
         return map.containsKey(o);   
     }   
     // 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap   
     public boolean add(E e)   
     {   
         return map.put(e, PRESENT) == null;   
     }   
     // 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素  
     public boolean remove(Object o)   
     {   
         return map.remove(o)==PRESENT;   
     }   
     // 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素  
     public void clear()   
     {   
         map.clear();   
     }  

    由上面源程序可以看出,HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。 
    HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。 

    TreeSet

    public class TreeSet<E> extends AbstractSet<E>
        implements NavigableSet<E>, Cloneable, java.io.Serializable

    测试

    package 集合类.Set类;  
    /** 
     * Set不允许重复数据 
     */  
      
      
    /** 
     * TreeSet 是用来进行集合排序的,请注意他和LinkedHashSet的区别。  
     TreeSet是按照一定的规则,将加入到集合里面的数据进行排序, 
     而LinkedHashSet是严格按照你放入集合的顺序进行使用 
     * @author jjj 
     */  
    import java.util.Arrays;  
    import java.util.Comparator;  
    import java.util.Set;  
    import java.util.TreeSet;  
      
    public class TreeSet类 {  
        public static void main(String[] args) {  
            // 测试自然排序  
            testNature();  
      
            // 测试指定排序方式  
            testComparator();  
      
            // 测试特殊的混合对象排序  
            testMix();  
        }  
      
        public static void testNature() {  
            // 测试一下数字  
            TreeSet<Integer> set = new TreeSet<Integer>();  
            // 反向存入整数数据  
            for (int i = 10; i >= 1; i--) {  
                set.add(i);  
            }  
            //如果add了相同的数据,是无效的,因为set集合不能重复元素  
            set.add(10);  
            // 输出看看  
            // 可以看到数据为自然的数字排序  
            showSet(set); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  
      
            // 测试一下字符串  
            TreeSet<String> set2 = new TreeSet<String>();  
            // 同样反向放入  
            for (int i = 10; i >= 1; i--) {  
                set2.add(i + "");  
            }  
            // 看输出结果  
            // 10 的自然排序没有2高,因为字符'1'小于'2'  
            showSet(set2); // [1, 10, 2, 3, 4, 5, 6, 7, 8, 9]  
      
            // TreeSet里面的数据因为要排队  
            // 所以如果是混合类型数据的数据,如果不能字段转换  
            // 将出现异常 java.lang.ClassCastException:  
        }  
      
        public static void testComparator() {  
            // 同样测试数字,我们要反向排序  
            TreeSet<Integer> set = new TreeSet<Integer>(new MyIntegerComparator());  
            // 反向存入整数数据  
            for (int i = 10; i >= 1; i--) {  
                set.add(i);  
            }  
            // 输出看看  
            // 可以看到数据为我们期望的反向排序了  
            showSet(set); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]  
      
            // 我们指定更奇怪的排序,奇数在前面,偶数在后面  
            // 我们使用匿名内部类  
            TreeSet<Integer> set2 = new TreeSet<Integer>(new Comparator<Integer>() {  
      
                public int compare(Integer o1, Integer o2) {  
                    if (o1 % 2 != 0) {  
                        if (o2 % 2 != 0) {  
                            return o2.compareTo(o1);  
                        }  
                        return -1;  
                    }  
                    if (o2 % 2 != 0) {  
                        return 1;  
                    }  
                    return o2.compareTo(o1);  
                }  
            });  
            // 反向存入整数数据  
            for (int i = 10; i >= 1; i--) {  
                set2.add(i);  
            }  
            // 输出看看  
            // 可以看到数据,技术的在前面,且从大到小排序  
            // 偶数在后面,也是从大到小排序  
            showSet(set2); // [9, 7, 5, 3, 1, 10, 8, 6, 4, 2]  
      
        }  
      
        /** 
         * 混合对象,你要为每个对象类型进行计较控制,避免出现转换异常. 
         */  
        public static void testMix() {  
            // 我们测试混合类型的对象,比如字符串和整数  
            // 如果我们不指定自己的比较器,而使用默认的自然比较器  
            // 将发生异常  
            TreeSet set = new TreeSet(new Comparator() {  
      
                public int compare(Object o1, Object o2) {  
                    // 我们用字符串比较好了  
                    return o1.toString().compareTo(o2.toString());  
                }  
      
            });  
            for (int i = 10; i >= 1; i--) {  
                set.add(i); // 存入整数  
                set.add(i + ""); // 存入字符串  
            }  
            // 输出看看  
            // 里面的内容确实按照字符串进行排序了。  
            // 数字被转化为字符串再参与比较。  
            showSet(set); // [1, 10, 2, 3, 4, 5, 6, 7, 8, 9]  
        }  
      
        /** 
         * 显示Set里面的数据。 
         *  
         * @param set 
         */  
        private static void showSet(Set set) {  
            System.out.println(Arrays.toString(set.toArray()));  
        }  
    }  
      
    // 注意,我指定了强制类型的比较器  
    class MyIntegerComparator implements Comparator<Integer> {  
      
        public int compare(Integer o1, Integer o2) {  
            return o2.compareTo(o1);// 使用反向的比较  
        }  
    }  

    Map接口

    public interface Map<K,V> 

      请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射

      Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。  

    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相关的值 。Map集合中的键对象不允许重复,也就说,任意两个键对象通过equals()方法比较的结果都是false.,但是可以将任意多个键独享映射到同一个值对象上。 

    Map的功能方法

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

    执行效率是Map的一个大问题。看看get()要做哪些事,就会明白为什么在ArrayList中搜索“键”是相当慢的。而这正是HashMap提高速 度的地方。HashMap使用了特殊的值,称为“散列码”(hash code),来取代对键的缓慢搜索。“散列码”是“相对唯一”用以代表对象的int值,它是通过将该对象的某些信息进行转换而生成的。所有Java对象都 能产生散列码,因为hashCode()是定义在基类Object中的方法。 

    HashMap就是使用对象的hashCode()进行快速查询的。此方法能够显着提高性能。 

    Map : 维护“键值对”的关联性,使你可以通过“键”查找“值”
    
    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。专为解决特殊问题而设计。

    Hashtable类
      Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。
      添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
      Hashtable通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。
      使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:

        Hashtable numbers = new Hashtable();
        numbers.put(“one”, new Integer(1));
        numbers.put(“two”, new Integer(2));
        numbers.put(“three”, new Integer(3));

      要取出一个数,比如2,用相应的key:

        Integer n = (Integer)numbers.get(“two”);
        System.out.println(“two = ” + n);

      由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。
      如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
      Hashtable是同步的。

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

    WeakHashMap类
      WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

    总结
      如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
      如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
      要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
      尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

    Collection 和 Map 的区别

    容器内每个为之所存储的元素个数不同。
    Collection类型者,每个位置只有一个元素。
    Map类型者,持有 key-value pair,像个小型数据库。

    其他特征

    List,Set,Map将持有对象一律视为Object型别。

    Collection、List、Set、Map都是接口,不能实例化。
        继承自它们的 ArrayList, Vector, HashTable, HashMap是具象class,这些才可被实例化。
    vector容器确切知道它所持有的对象隶属什么型别。vector不进行边界检查。

    总结

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

    注意:
    1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
    2、Set和Collection拥有一模一样的接口。
    3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
    4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
    5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
          HashMap会利用对象的hashCode来快速找到key。
    6、Map中元素,可以将key序列、value序列单独抽取出来。
    使用keySet()抽取key序列,将map中的所有keys生成一个Set。
    使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。
  • 相关阅读:
    English 2
    速算24点
    心理学1
    从微服务到函数式编程
    034 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 01 流程控制概述
    033 01 Android 零基础入门 01 Java基础语法 03 Java运算符 13 运算符和表达式知识点总结
    032 01 Android 零基础入门 01 Java基础语法 03 Java运算符 12 运算符和if-else条件语句的综合案例——闰年问题
    031 01 Android 零基础入门 01 Java基础语法 03 Java运算符 11 运算符的优先级
    030 01 Android 零基础入门 01 Java基础语法 03 Java运算符 10 条件运算符
    029 01 Android 零基础入门 01 Java基础语法 03 Java运算符 09 逻辑“非”运算符
  • 原文地址:https://www.cnblogs.com/hwaggLee/p/4510589.html
Copyright © 2011-2022 走看看