zoukankan      html  css  js  c++  java
  • Java集合框架学习笔记

    集合类的由来:

      对象用于封装特有数据,对象多了需要存储,如果对象的长度不确定,就使用集合存储。

      集合特点

        1、用于存储对象的容器。

        2、集合的长度可变。

        3、集合中不可以存储基本类型


      集合容器因为内部的数据结构不同,有多种具体容器。不断的向上抽取就形成了集合框架

      框架的顶层就是:Collection接口。
      顶层抽出的共有方法:
        1、添加

        2、删除

        3、判断

        4、获取

      Iterator iterator();获取元素的方式 :迭代器

      迭代器的使用:

      使用for循环节省内存   循环结束后it不会驻留在内存中

      如果用While   迭代器会驻留在内存中

      for(Iterator it = coll.iterator();it.hasNext();){
        System.out.println(it.next());
      }

      迭代器原理:

        该对象必须依赖于具体容器,因为每一个容器的数据结构都不相同。

        所以该迭代器对象是在容器中进行内部实现的

        对于使用容器者而言,具体的实现并不重要,只要通过容器获取到该实现的迭代器的对象即可。

        也就是iterator方法。

      Iterator接口就是对所有的Collection容器进行元素取出的公共接口

        MyEclipse快捷键:

          查看接口的实现类:Ctrl+T

              查看类或方法的引用 Ctrl+Shift+G

              查看类的声明:F3

        5、其它

          retainAll(Collection coll)  获取两个集合中的交集

          注意:retainAll与removeAll,removeAll删除集合中含有的所有对象.

          eg:c1={1,2,3} c2={2,3,4} 吧c2放入c1中   removeAll后得到{1}

            retainAll后{2,3}

    Collection  下面的两个重要的子接口:

      |--List:有序(存入和读出的顺序一致),元素都有索引,元素可以重复

      |--Set:元素不能重复。(与List最大不同) 无序(也有可能出现有序的)

    List:常见方法-->Collection有的List都有

      特有方法:

        修改:Object set(index,element);

        获取:Object get(index);

          int indexOf(Object o);

          int lastIndexOf(Object o);

          List<E> subList(int fromIndex, int toIndex);(包头不包尾)

      总结:List可以对元素进行增删改查

      注意:进行集合操作时候不进行迭代操作,进行迭代操作时候不进行集合操作

           否则会出现对该对象进行了并发修改,但是不允许修改时候会报这种错误

           改进方法-->迭代的时候不要使用iterator();方法。要使用listIterator();方法进行迭代 

           此方法为Iterator接口下面的子接口的方法的实现。


    List接口下面的实现类:

      |--Vector:(内部数据结构为数组数据结构,是同步的,意味着线程安全,但是效率低,现在已经基本上不用)注:最早的单列集合

        Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。

        但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。

        增删查都很慢

      遍历Vector的方法有三种(较ArrayList和LinkedList多出一种)

      枚举遍历:

      Enumeration en = Vector.elments();

      Enumeration 有两个方法 hasMoreElement();nextElement()

      while(vector.hasMoreElements()){
    
        System.out.println(vector.nextElement)
    
      }

      关于Enumeration:

        此接口的功能与 Iterator 接口的功能是重复的。此外,Iterator 接口添加了一个可选的移除操作,并使用较短的方法名。

        新的实现应该优先考虑使用 Iterator 接口而不是 Enumeration 接口。

      |--ArrayList(内部数据结构为数组数据结构,是不同步的。效率高。所以替代了Vector。如果是多线程 给ArrayList加锁)

        可变长度数组实现原理,ArrayList会提前生成一个固定长度数组,如果大小不够大,新生成一个数组增加原来数组的一半。

        读、查询速度快

      |--LinkedList(内部数据结构为链表,非同步,效率高)

        增删元素速度快

        特有方法:addFrist(); addLast();

        理解:因为LinkedList内部数据结构为链表,所以中间都是一环扣一环,但是头和尾部不是,所以很好添加新元素。

        getFirst();获取但不删除 removeFirst();获取但是删除

        重点:用LinkedList模拟堆栈或者队列的数据结构

      堆栈:

        栈特点:先进后出

      队列:

        特点:先进后出

      实现:描述一个容器,给使用者提供一个容器对象完成这两种结构中的一种。

    class MyQuere{
                        private LinkedList link;
                        MyQuere{
                            link = new LinkedList();
                        }
                        public void myAdd(Object obj){
                            link.addLast(obj);
                        }
                        public Object myGet(){
                            return link.removeFirst();
                        }
                        public boolean isNull(){
                            return link.isEmpty();
                        }
                    }
                    class MyStack{
                        private LinkedList link;
                        MyQuere{
                            link = new LinkedList();
                        }
                        public void myAdd(Object obj){
                            link.addLast(obj);
                        }
                        public Object myGet(){
                            return link.removeLast();
                        }
                        public boolean isNull(){
                            return link.isEmpty();
                        }
                    }

     

        LinkdList---->JDK1.6新特性与1.5对比

          addFirst();addLast();-->无返回

          offerFirst();offerLast();   -->在此列表插入指定的元素。返回:true(根据 Deque.offerFirst(E) 的规定)(1.6新特性)

          getFirst();getLast();    -->NoSuchElementException - 如果此列表为空.

          peekFirst();peekLast();  -->此列表的第一个元素;如果此列表为空,则返回 null.(1.6新特性)

          removeFirst();removeLast();  -->无返回

          pollFirst();pollLast();   --> 获取并移除此一个元素;如果此列表为空,则返回 null。(1.6新特性)

        总结:以上方法都来自于接口Quere,1.6新特性中的方法有特殊返回值。特殊返回值可以用来做判断标识。

        补充:什么时候自动装箱?

          基本类型值赋值给了对象引用的时候会自动装箱。


    Set:一个不包含重复元素的 collection。

      更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。无序的。

      Set接口中的方法与Collection中的方法一致。

      注意:Set取数只有一种方式:迭代器Iterator

      |--HashSet   保证唯一的特点。该容器中不会有重复的对象。

        此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序.

        内部结构数据为哈希表,是不同步的。

      补充:哈希表-->实质还是数组

        一般数组的存入都是以脚标来存入,查找的时候顺序对比,产生结果。

        而哈希表在存入的时候会按照存入的对象的特性,存入指定的位置(无序的原因)

        function(Element){
    
          一个算法,这个算法,对元素进行运算,并获取其位置。
    
          注意:此算法就是hashcode();这个方法是由底层的windows做的,看不到。
    
          我们可以做自己的算法:(简易原理实现:以字符串为例)另数组长度为10 即:0-9;
    
          存放"ab"根据ab的asc值97+98=195   
    
          让195%10=5   ---->找到下标为5的位置进行比较,有就是有,没有就是没有。
    
          ---->插入的时候,当有5存在的时候就不会插入(这就是为什么Set不会有对象重复的原因)
    
          ---->注意:并不能说明地址(下标)相同就是相同的内容(例如:"ba")
    
          ---->所以当地址(下标)相同的时候,再要比较内容。
    
          return index;
    
        }

        当要获取的时候再用一次该方法获取其位置,直接找到该元素。

        总结哈希表:

          哈希表确定元素是否相同

          1.判断两个元素的哈希值是否相同。如果相同,进而比较两个对象的内容是否相同。

          2.判断哈希值是否相同,其实判断的是对心的hashCode();的方法。

          判断内容是否相同用的是equals();方法。

          注意:如果哈希值不同,则不需要判断内容是否相同。

          如果哈希值相同,但是内容不同(这种情况是很少的,因为哈希算法非常复杂,叫做哈希冲突),解决办法很多,可以顺延。

        自定义对象的存储:(重点)

          HashSet集合数据结构是哈希表,所以使用hashCode();方法来确定位置;如果位置相同,用equals();方法来确认内容是否相同。

          如果不重写hashCode()方法,那么会调用父类(Object)的hashCode()方法。

          如果不重写equals()方法,那么也会调用父类(Object)的equals()方法。父类的equals()方法比较的是地址,而没创建一个对象

          肯定有一个新地址,所以equals()肯定不会相同,所以即便内容会相同,也会储存。

      ArrayList和HashSet的区别:

        ArrayList判断对象依赖的是equals();方法。

        而HashSet判断对象用到的是hashCode();方法和equals();方法

        所以当用ArrayList的remove()方法的时候,虽然对象的地址(下标)不同,但是只要内容相同,都会移除。

        而HashSet就要用到hashCode()和equals()两个方法。

        当我们想要保证对象唯一,并且还想要有序。在Set下面提供了一个实现类-->LinkedHashSet<E>

        定义:

          具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。

          此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。

          链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。

        注意,插入顺序不 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)

        理解:就是HashSet与链表相结合。


    |--TreeSet

      使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

      即:要想对自定义对象排序,必须将该类实现Comparator类,并实现其方法:compareTo()。

      int compareTo(Object o){
    
        比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
    
        1、比较数值的时候,直接用逻辑符号>、<、=来判断。
    
        2、比较字符串的时候,可以用public int compareTo(String anotherString)方法。
    
        技巧:做差。
    
      }

      重要:判断元素唯一行的方法,就是根据比较方法的返回结果是否是0,如果是0,就是相同元素,不存。

      总结:

        TreeSet对元素进行排序的方式之一:

          让元素自身具备比较功能,元素需要实现Comparator接口,并且覆盖compareTo()方法。

          如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序怎么办?

        可以使用TreeSet的第二种排序方式:

          让集合自身具备排序功能。集合创建时就要有。即:构造方法。

          创建一个比较器,实现Comparator接口。实现compare()方法:两两元素进行比较。

        两种方式的区别:

          第一种是利用元素自身的比较方法比,只需要传入一个元素即可。

          第二种是利用集合自身的比较,要传入两个元素。

        两个都存在的情况下面以构造器为主。实际开发用第二种比较多。

      底层数据结构:

        经典二叉树:当保存的时候使用二叉树保存,大的在右边,小的在左部。

        int compare(Object o1,Object o2){ // 比较用来排序的两个参数。
    
          根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
    
          如果指定返回一个正整数,则意味着存入的时候都往二叉树的右侧存,即有了一定的顺序:插入的顺序是怎么样的,查询的顺序就是怎么样的。
    
        }

      注意:只要不是按照自然排序就利用比较器


     

    Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

      与Collection区别:Map一次添加一对元素,Collection一次添加一个元素;Map也称为双列集合,Collection也称为单列集合。

      根据定义:Map必须保证键的唯一性。

      常用方法:

        1、添加

          V put(K key, V value):返回前一个key关联的值,如果没有返回null。

          理解:如果该key之前没有对应的值,那么返回null,并且成功存入。如果key之前有值,那么返回之前的值(即把原来的值删除),并存入当前的值。

        2、删除

          void clear() 清空map集合

          V remove(Object key):根据key值删除键值对

        3、判断

          boolean  containsKey(Object key):有键吗? 

          boolean  containsValue(Object value) :有值吗?

          boolean  isEmpty() :存在吗?

        4、获取

          V get(Object key) :通过键获取值。如果没有该键返回null。

          int size() :返回键值对个数。

        5、遍历

          第一种:

            Set<K>  keySet() :得到所有键。-->既然是Set集合,那么就可以用迭代器迭代,为什么不反悔List?因为List不唯一。

          第二种:

            Set<Map.Entry<K,V>>entrySet(): 返回此映射中包含的映射关系的 Set 视图。(entry :登记)

            原理:将键值对两个对象,封装成一个对象

            补充:内部接口

            Map接口下面有一个内部接口Entry

              interface Map{
                interface Entry{
                  public void get();
                }
              }

          为什么要这么做?因为Entry是将键值对封装成一个对象,如果要用Entry那么前提肯定是Map,外部规则中有内部规则,内部规则访问外部规则的内容。

          所以要写成内部接口的形式。

          Collection<V>  values() :为什么返回Collection?因为键虽然唯一,但是值不唯一。

      常用子类:

        |--Hashtable:内部数据结构哈希表,是同步的。表注:最早的双列集合   重点:不允许null作为键,不允许null作为值。

          Properties:Properties 类表示了一个持久的属性集。用来存储键值对形式的配置文件。可以和I/O技术相结合才能发挥最大的水平。

        |--HashMap:内部结构是哈希表,不是同步的。允许null作为键,允许null作为值。(与Hashtable的主要区别)

      LinkedHashMap<K,V>:

        Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。

        此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。

        此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。

        注意,如果在映射中重新插入 键,则插入顺序不受影响。

        |--TreeMap:内部结构是二叉树,不同步,可以对Map集合中的键进行排序

          注意:HashSet此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。

        Map集合练习:

          获取字符串中每个字符出现的次数。

        Utilities:

          工具类:便捷开发。

        |--Collections

          此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。

          扩展:自定义排序方法

          public static <T extends Comparable<? super T>> void MySort(List<T> list){
            说明:<T extends Comparable<? super T>>  加限制,因为要保证调用该方法的集合可以比较。
          }

    补充:

      Comparable接口与Comparator接口的区别:

        Comparable 是排序接口。

          若一个类实现了Comparable接口,就意味着“该类支持排序”。

          即然实现Comparable接口的类支持排序,假设现在存在“实现Comparable接口的类的对象的List列表(或数组)”,则该List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。

        Comparator 是比较器接口。

          我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);

          那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。

          Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序。

          所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

          Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。

        |--Arrays  

          此类包含用来操作数组(比如排序和搜索)的各种方法。此类还包含一个允许将数组作为列表来查看的静态工厂。

          除非特别注明,否则如果指定数组引用为 null,则此类中的方法都会抛出 NullPointerException。

          注意:

            数组转集合

            static <T> List<T>asList(T... a) :返回一个受指定数组支持的固定大小的列表。

            此方法同 Collection.toArray() 一起,充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。

            返回的列表是可序列化的,并且实现了 RandomAccess。

            注意:

              转换之后的List集合不能进行增删操作,因为数组为固定长度。

              如果数组中的元素是对象,那么转成集合时,直接将【数组中的元素】作为集合中的元素进行存储。

              如果数组中的元素是基本数据类型,那么在转成集合时,会将【数组】作为集合中元素进行存储。

              因为集合中不能存储基本数据类型,所以在转型的时候,List的泛型要注意:之前数组怎么定义的,泛型就怎么写。

            集合转数组

            Collection接口中的Object[]toArray()和<T> T[] toArray(T[] a)方法。

            集合转成数组,可以对集合中的元素进行限定,不允许增删。

        补充:给非同步的集合加锁。

    class MyCollections{
      public List synList(List list){
        return new MyList(list);
      }
    
      class MyList implements List{
        private List list;
        private static final Object lock = new Object(); 
        MyList(List list){
          this.list = list;
        }
        public boolean add(Object obj){
          synchronized(lock){
            return list.add(obj);
          }
        }
        public boolean remove(Object obj){
          synchronized(lock){
            return list.remove(obj);
          }
        }
        ...//实现其他方法并且都加锁。
      }  
    }

     

  • 相关阅读:
    学习进度笔记4
    学习进度笔记3
    学习进度笔记2
    学习进度笔记1
    《梦断代码》提及文献
    《梦断代码》阅读笔记6
    《梦断代码》阅读笔记5
    需求征集系统开发进度5
    《梦断代码》阅读笔记4
    spark filter
  • 原文地址:https://www.cnblogs.com/snoopylovefiona/p/4679884.html
Copyright © 2011-2022 走看看