1. 程式人生 > >深入理解java集合的底層操作

深入理解java集合的底層操作

集合:層次結構:

(1)Collection (介面)其常用子介面 Set    List  Queue 

Set 的子介面和其實現類如下

(一)EnumSet (抽象類)  implements  Set   

(二)SortedSet(介面)     exntends  Set   

(三)HashSet                       implements  Set  

(一.1)EnumSet的元素加入儲存的機制是:當建立EnumSet物件 EnumSet e=new EnumSet(Season.class)時就把Season型別的列舉值賦給EnumSet屬性final Enum[] universe了

;進行add(Object o)時,先呼叫typeCheck(e)進行型別檢查,如型別不是Season或者其父類時則丟擲異常,然後 return elements != oldElements;實際上沒有加入任何元素,所以EnumSet中只可以存放相同列舉型別的物件,否則會丟擲型別轉換異常,

add的原始碼如下:

public boolean add(E e) {
        typeCheck(e);

        long oldElements = elements;
        elements |= (1L << ((Enum)e).ordinal());
        return elements != oldElements;
    }

刪除時實際也沒有刪除任何元素:程式碼如下

public boolean remove(Object e) {
        if (e == null)
            return false;
        Class eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false;

        long oldElements = elements;
        elements &= ~(1L << ((Enum)e).ordinal());
        return elements != oldElements;
    }

(二.1)TreeSet                     implements    SortedSet

(三.1)LinkedHashSet       exntends  HashSet 

HashSet類中加入元素(可以加入不同型別的元素)的機制是根據其元素的equals(Object o)方法和hashCode()方法來判斷是否能夠加入新的元素,HashSet中的元素是無序的

LinkedHashSet的原理和HashSet的相同,只是LinkedHashSet是有序的,先加入的排在前面,底層通過連結串列來維護這種順序。

由於HashSet和LinkedHashSet類加入和刪除元素的機制是根據add(Object obj)加入物件obj的hashCode()的hash值和equals(Object o)進行比較是否可加入新元素或者存在該元素,由於所有的類的hash值都是整數,是可比較的,並且所有類預設的equals(Object o)方法都可以與任何型別的物件進行比較,如果是與不同型別的物件進行比較時,返回的值是false,所以HashSet和LinkedHashSet類中可加入不同型別的元素,如:

package set;

import java.util.HashSet;
import java.util.Iterator;

public class hashset
{
public static void main(String[] args)
{
 HashSet h=new HashSet();
 h.add("hello");
 h.add("world");
 h.add("good");
 h.add("ddd");
 h.add("aaa");
 h.add("hello");
 h.add(new hashset());
 h.add(new Integer(4));
 System.out.println(new hashset().hashCode());
 Iterator it=h.iterator();
 while(it.hasNext())
 {
  System.out.println(it.next());
 }
}
}

即可加入String型別也可加入hashsett和Integer型別

TreeSet類中加入元素(元素必須是同種型別)的機制是根據其元素對應的類中實現Comparable介面的compareto(Object o)方法來判斷是否能夠加入新的元素,如果該元素對應的類中沒有實現該方法,則TreeSet中能加入一個元素,TreeSet預設是根據compareto(Object  o)來對元素進行升序排序,也可以實現定製排序

如 TreeSet<R> t=new TreeSet(new Comparator<R>()
 {
     @Override
     public int compare(R o1, R o2)
     {
              return o1.count>o2.count?-1:o1.count<o2.count?1:0;              
     }
 });

TreeSet的儲存機制是用紅黑樹進行儲存的,如下程式碼的儲存:

package test;

import java.math.BigDecimal;
import java.util.TreeSet;
class R implements Comparable
{
 int count;
 public R(int count)
 {
  this.count=count;
  
 }
 public String toString()
 {
  return "R[count:"+count+"]";
 }
 public boolean equals(Object o)
 {
  if(this==o)
   return true;
  if(o!=null&&o.getClass()==R.class)
  {
   R r=(R)o;
   if(this.count==r.count)
    return true;
  }
   return false;
 }
 @Override
 public int compareTo(Object o)
 {
            R r=(R)o;
           return count>r.count?1:count<r.count?-1:0;
 }
}

public class Test
{

public static void main(String[] args)
{
    TreeSet<R> t=new TreeSet();
    t.add(new R(5));
    t.add(new R(-3));
    t.add(new R(9));
    t.add(new R(-2));
    System.out.println(t);  (1)
    R first=t.first();
    first.count=20;
    R last=t.last();
    last.count=-2;           
   
    System.out.println(t);   (2)
    System.out.println(t.remove(new R(-2)));
    System.out.println(t);
    System.out.println(t.remove(new R(5)));
    System.out.println(t);
    System.out.println(t.remove(new R(-2)));
    System.out.println(t);
}
}
(1)之前的紅黑樹是這樣的:

            5

-3                   9

        -2

(1)-->(2)樹新增修改穩定之後,形成的紅黑樹是這樣的:

          5

20              -2
      -2

第二層-2是20的右子節點,因為刪除時循根搜尋,-2一直往左路搜,最後搜到20左子節點為空,所以刪除失敗,待5刪除之後,重新平衡了樹結構:

     -2

20      -2

因此-2就能被刪除

TreeSet中刪除元素的原理t.remove(Object obj) :

通過呼叫obj物件對應類中的obj.compareTo(Object obj)方法,按照紅黑樹搜尋的方法來查詢,如果存在obj.compareTo(Object obj1)返回值等於0,則刪除掉該obj1元素,否則刪除不成功

TreeSet中加入不同型別元素的異常問題

package set;

import java.util.Iterator;
import java.util.TreeSet;

public class treeset implements Comparable
{
 @Override
  public int compareTo(Object o)
  {
  return 1;
  }
 public static void main(String[] args)
{
 TreeSet t=new TreeSet();
 t.add(new Integer(2));//由於還沒有元素,所有可以加入
 t.add(new Integer(3));//由於t中只存在Integer型別元素,所以可以繼續加入
 t.add(new treeset());//雖然集合中存在Integer型別元素,但由於treeset中實現了comparaTo(Object o)方法該方法的返回值總是1,所有總是可比較的
 //t.add(new String());//出現異常,因為String 中實現的comparaTo(Object o)方法,只可以和String型別比較,由於集合中存在其他型別(Integer和treeset型別),所有丟擲型別轉換異常
}

List 的子介面和其實現類如下   List有序,可重複,可以獲得ListIterator it=al.listIterator();ListIterator迭代器,可進行向前迭代

(一)LinkedList  implements List

(二)ArrayList     implements List

(三)Vector         implements List                      Stack extends Vector

 ArrayList 中加入元素的儲存機制是根據索引來儲存的,每個元素都有一個索引,所以ArrayList中可以加入相同的元素,她們的索引是不同的,並且是有序的,ArrayList刪除的原理是根據remove(Object obj)中obj所對應的類的equals(Object o)方法來判斷的,如果返回值是true,則刪除對應的元素o,由於所有類預設的equals(Object o)方法都可以與任何型別的物件進行比較,如果是與不同型別的物件進行比較時,返回的值是false,所以ArrayList中可加入不同型別的元素,如:

package list;

import java.util.ArrayList;
import java.util.List;

public class arraylist
{
public static void main(String[] args)
{
 List l=new ArrayList();
 ArrayList al=new ArrayList();
 al.add("hello");
 al.add("www");
 al.add(new arraylist());
 al.add(new Integer(4));
 al.add("www");
 al.add(0, "good");
 System.out.println(al.get(3));
 
}
}
即可加入String型別也可加入arraylist和Integer型別

 由於arraylist重寫了equals(Object o)方法,並且返回值總是true,所以當remove(Object obj)時總是刪除集合中的第一個元素,不管obj是否存在

package list;

import java.util.ArrayList;
import java.util.List;

public class arraylist
{
 public boolean equals(Object o)
 {
  return true;
 }
public static void main(String[] args)
{
 List l=new ArrayList();
 ArrayList al=new ArrayList();
 al.add("hello");
 al.add("www");
 al.add("www");
 al.add(0, "good");
    al.remove(new arraylist());
    al.remove(new arraylist());
    System.out.println(al);
 
}
}

Vector的用法和ArrayList幾乎完全相同,Vector是古老的方法,Vector中有比較多的重複的方法,Vector是執行緒安全的,ArrayList是執行緒不安全的,儘量少用Vector,如果為了執行緒安全,則可以通過

 ArrayList  ar=(ArrayList)Collections.synchronizedList(new ArrayList());來確保ArrayList的執行緒安全

Stack實現了Vector類,比Vector類多了三個方法push(Object o),入棧,pop()出棧,peek()檢視棧頂元素,由於Stack也是古老的方法,所以儘量少用,如果要用“棧”這種資料結構,則可以用LinkedList類

固定長度的List

package list;

import java.util.Arrays;
import java.util.List;

//Arrays的內部類ArrayList的測試,該List是不可變,只能遍歷,不能增加和刪除
public class Arrays_ArrayList
{
public static void main(String[] args)
{
 //=Arrays.asList(T... a)返回的是Arrays的內部類ArrayList,而不是由實現了List介面的ArrayList、LinkedList或者Vector
 List l=Arrays.asList("heelo","good");//該集合中的元素是用/Arrays的內部類ArrayList的 private final E[] a屬性來存放的;由於a是final修飾的,所以不能刪除a中的元素;
 //l.remove(0);丟擲異常
 System.out.println(l);
 l.set(0, "wolrd");//可以改裡面的元素內容
 
}
}

Queue 的子介面和實現類如下:

(一)Deque  extends  Queue   LinkedList implements Deque

 (二)   PriorityQueue  implements Queue

LinkedList 加入是根據索引加入,所以能加入重複元素,刪除remove(Object o)是根據元素o所對應的類的equals方法來查詢刪除的,所以可以加入不同型別的元素

PriorityQueue 加入元素的策略是通過佇列中元素對應類的compareTo(Object o)方法進行比較,升序排序,當加入的元素比對尾的元素小時則和隊尾的元素交換位置,直到找到該元素的存放位置為止,如果加入的元素大於或者等於隊尾元素時,則直接把該元素加入到隊尾,所以可以加入值相等的元素,由於不同類實現的compareTo(Object o)方法只能進行同種類型物件的比較,所以PriorityQueue 中只能加入同種型別的資料

加入的底層程式碼實現如下:

PriorityQueue q=new PriorityQueue();
 q.add(8);
 q.add(8);

 public boolean add(E e) {
        return offer(e);
    }

add呼叫了offer(e)方法

offer(e)的方法如下
 public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
       
return true;
    }

  siftUp(i, e)方法如下

private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

siftUpComparable(k, x)方法如下

  private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

由(key.compareTo((E) e) >= 0)break;
可知。當該元素大於或等於隊尾元素時,直接加入該元素,所以可以加入重複的元素

刪除則是根據equals方法來查詢刪除的

相關推薦

深入理解java集合底層操作

集合:層次結構: (1)Collection (介面)其常用子介面 Set    List  Queue  Set 的子介面和其實現類如下 (一)EnumSet (抽象類)  implements  Set    (二)SortedSet(介面)     exntends

深入理解JAVA集合系列四:ArrayList源碼解讀

結束 了解 數組下標 size new 數組元素 開始 ini rem 在開始本章內容之前,這裏先簡單介紹下List的相關內容。 List的簡單介紹 有序的collection,用戶可以對列表中每個元素的插入位置進行精確的控制。用戶可以根據元素的整數索引(在列表中的位置)訪

深入理解JAVA集合系列三:HashMap的死循環解讀

現在 最新 star and 場景 所有 image cap 時也 由於在公司項目中偶爾會遇到HashMap死循環造成CPU100%,重啟後問題消失,隔一段時間又會反復出現。今天在這裏來仔細剖析下多線程情況下HashMap所帶來的問題: 1、多線程put操作後,get操作導

深入理解Java集合框架》系列文章

stack 數據結構 tro www. rpe ack 不能 一個 標準 https://www.cnblogs.com/CarpenterLee/p/5545987.html Introduction 關於C++標準模板庫(Standard Template Libr

深入理解Java集合框架】紅黑樹講解(上)

時間復雜度 row lee tel framework 關系 eight logs return 來源:史上最清晰的紅黑樹講解(上) - CarpenterLee 作者:CarpenterLee(轉載已獲得作者許可,如需轉載請與原作者聯系) 文中所有圖片點擊之後均可查看大

深入理解java集合】-ArryList實現原理

一、ArrayList簡介 1、概述 ArrayList是基於陣列實現的,是一個動態陣列,其容量能自動增長,類似於C語言中的動態申請記憶體,動態增長記憶體。 ArrayList不是執行緒安全的,只能用在單執行緒環境下,多執行緒環境下可以考慮用Collections.

深入理解java集合】-LinkedList實現原理

一、LinkeddList簡介 1、LinkedList概述 LinkedList是一個一個繼承於AbstractSequentialList,並實現了List介面和Deque介面的雙端連結串列。 LinkedList底層的連結串列結構使它支援高效的插入和刪除操作,

深入理解java集合】-TreeMap實現原理

一、紅黑樹介紹 1、R-B Tree概念 紅黑樹(Red Black Tree,簡稱R-B Tree) 是一種自平衡二叉查詢樹,它雖然是複雜的,但它的最壞情況執行時間也是非常良好的,並且在實踐中是高效的: 它可以在O(log n)時間內做查詢,插入和刪除,這裡的n 是

深入理解Java集合之List

List筆錄List相較於set、map,是按照一定順序儲存,List主要分為3類,ArrayList, LinkedList和Vector。以下是List的結構圖,本文章重點講解ArrayList與LinkedList的底層實現原理。ArrayListArrayList採用

1.深入理解java集合List

下圖是java集合框架圖,Collection、Map是集合框架的頂級類,Iterator是集合迭代器。 Collection介紹(主要講解實現類,主要特點,適用場景,實現原理) 1、List介面,主要實現類Vector、ArrayList、LinkedList    

深入理解Java集合之Map

Map筆錄    Map 提供了一個更通用的元素儲存方法。 Map 集合類用於儲存元素對(稱作“鍵”和“值”),其中每個鍵對映到一個值。標準的Java類庫中包含了Map的幾種基本實現,包括HashMap、TreeMap、LinkedHashMap、WeakHashMap、Co

深入理解Java集合

集合 集合類存放於java.util包中。 集合型別主要有3種:set(集)、list(列表包含Queue)和map(對映)。 Collection:Collection是集合的基本介面,List、Set、Queue的最基本的介面。 Iterator:迭代器,可以通過迭代

深入理解Java中的底層阻塞原理及實現

更多 安全 posix pla static events time() 方便 原理 談到阻塞,相信大家都不會陌生了。阻塞的應用場景真的多得不要不要的,比如 生產-消費模式,限流統計等等。什麽 ArrayBlockingQueue、 LinkedBlockingQueue、

深入理解Java中的同步靜態方法和synchronized(class)程式碼塊的類鎖 深入理解Java併發synchronized同步化的程式碼塊不是this物件時的操作

一.回顧學習內容  在前面幾篇部落格中我我們已經理解了synchronized物件鎖、物件鎖的重入、synchronized方法塊、synchronized非本物件的程式碼塊,  連結:https://www.cnblogs.com/SAM-CJM/category/1314992.h

深入理解Java併發synchronized同步化的程式碼塊不是this物件時的操作

一.明確一點synchronized同步的是物件不是方法也不是程式碼塊   我有關synchronized同步的是物件討論的部落格在這裡:https://www.cnblogs.com/SAM-CJM/p/9798263.html  只要明確了synchroni

深入理解Java集合框架

1. 概述 Java集合框架由Java類庫的一系列介面、抽象類以及具體實現類組成。我們這裡所說的集合就是把一組物件組織到一起,然後再根據不同的需求操縱這些資料。集合型別就是容納這些物件的一個容器。也就是說,最基本的集合特性就是把一組物件放一起集中管理。根據集合中是否允許有重

深入理解java對映map的底層

對映:層次結構: (1)Map (介面)其子介面和其實現類如下 (一)EnumMap(抽象類)  implements  Map (二)SortedMap(介面)     exntends  Map           TreeMap extends SortedMap 

深入學習java集合系列】LinkedHashMap的底層實現

最近寫到LeetCode上的某一題LRUCache。可以採用LinkedHashMap實現,通過重寫removeEldestEntry方法,即可實現。 LinkedHashMap map; public LRUCache(int capacity) {

深入理解Java虛擬機- 學習筆記 - 虛擬機類加載機制

支持 pub eth 獲取 事件 必須 string 沒有 字節碼 虛擬機把描述類的數據從Class文件加載道內存,並對數據進行校驗,轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。在Java裏,類型的加載、連接和初始化過程都是在程序

JVM運行時數據區--深入理解Java虛擬機 讀後感

出棧 很好 棧幀 最大 出錯 生命周期 所有 img 就會 程序計數器 程序計數器是線程私有的區域,很好理解嘛~,每個線程當然得有個計數器記錄當前執行到那個指令。占用的內存空間小,可以把它看成是當前線程所執行的字節碼的行號指示器。如果線程在執行Java方法