再談Java資料結構—分析底層實現與應用注意事項
在回顧js資料結構,寫《再談js物件資料結構底層實現原理-object array map set》系列的時候,在來整理下java的資料結構。
java把記憶體分兩種:一種是棧記憶體,另一種是堆記憶體
-
基本型別在棧區分配空間,java的基本資料型別共有8種,即int,short,long,byte,float,double,boolean,char(注意,並沒有String的基本型別 )。由於大小可知,生存期可知(這些字面值定義在某個程式塊裡面,程式塊退出後,欄位值就消失了),出於追求速度的原因,就存在於棧中。
-
所有的物件都在堆(Heap)中分配空間,關鍵字new為每個物件申請記憶體空間(基本型別除外),物件的釋放是由垃圾回收機制決定和執行的,這樣做確實簡化了程式設計師的工作。但同時,它也加重了JVM的工作。因為,GC為了能夠正確釋放物件,GC必須監控每一個物件的執行狀態,包括物件的申請、引用、被引用、賦值等,GC都需要進行監控。
不要在經常呼叫的方法中或在迴圈中建立物件。可以適當的使用hashtable,vector建立一組物件容器,然後從容器中去取那些物件,而不用每次new之後又丟棄。儘量避免在類的建構函式裡建立、初始化大量的物件,防止在呼叫其自身類的構造器時造成不必要的記憶體資源浪費,尤其是大物件
包裝類
基本型別都有對應的包裝類:如int對應Integer類,double對應Double類等,基本型別的定義都是直接在棧中,如果用包裝類來建立物件,就和普通物件一樣了。例如:int i=0;i直接儲存在棧中。Integer i(i此時是物件)= new Integer(5);這樣,i物件資料儲存在堆中,i的引用儲存在棧中,通過棧中的引用來操作物件。大量使用字串處理,避免使用String,應大量使用StringBuffer,因為String被設計成不可變(immutable)類,所以它的所有物件都是不可變物件
陣列
當定義一個數組,int x[];或int[] x;時,在棧記憶體中建立一個數組引用,通過該引用(即陣列名)來引用陣列。x=new int[3];將在堆記憶體中分配3個儲存 int型資料的空間,堆記憶體的首地址放到棧記憶體中,每個陣列元素被初始化為0。
靜態變數
用static的修飾的變數和方法,實際上是指定了這些變數和方法在記憶體中的”固定位置”-static storage,可以理解為所有例項物件共有的記憶體空間。static變數有點類似於C中的全域性變數的概念;靜態表示的是記憶體的共享,就是它的每一個例項都指向同一個記憶體地址。把static拿來,就是告訴JVM它是靜態的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不會變成原樣,你把它清理了,它就不會回來了。
那靜態變數與方法是在什麼時候初始化的呢?對於兩種不同的類屬性,static屬性與instance屬性,初始化的時機是不同的。instance屬性在建立例項的時候初始化,static屬性在類載入,也就是第一次用到這個類的時候初始化,對於後來的例項的建立,不再次進行初始化。
儘量少用靜態變數,因為靜態變數是全域性的,GC不會回收的。
陣列Array和集合的區別
-
1 長度限制之別
-
陣列長度是固定不變的,
-
集合的大小是可動態變化的
-
-
2 儲存型別之別
-
一個數組儲存的元素可以是基本型別,也可以是引用型別,且只能儲存同一種類型的元素
-
一個集合儲存的元素只能是引用型別,但集合可以儲存不同型別的元素(但集合一般儲存同一種類型,可以用泛型加以控制)
-
-
3 訪問元素方式
-
陣列是根據索引來獲取元素的
-
集合通常會提供一個迭代器來方便訪問元素
-
若程式時不知道究竟需要多少物件,需要在空間不足時自動擴增容量,則需要使用容器類庫,array不適用。
java集合是什麼?
Java集合類存放於 java.util 包中,是一個用來存放物件的容器。
-
長度限制之別:集合只能存放物件。比如你存一個 int 型資料 1放入集合中,其實它是自動轉換成 Integer 類後存入的,Java中每一種基本型別都有對應的引用型別。
-
集合存放的是多個物件的引用,物件本身還是放在堆記憶體中。
-
集合可以存放不同型別,不限數量的資料型別。
史上最全Java集合關係圖 ,java集合關係UML類圖vsdx原圖。
Collection
|-----List 有序,可重複(儲存順序和取出順序一致)
|--|----LinkedList 底層使用雙向連結串列實現,查詢慢,增刪快。效率高
|--|----ArrayList 底層使用陣列實現,查詢快,增刪慢。效率高。
| | 每次容量不足時,自增長度的一半,如下原始碼可知
| | int newCapacity = oldCapacity + (oldCapacity >> 1);
|--|----Vector 底層使用陣列實現,執行緒安全,查詢快,增刪慢。效率低。
| | 每次容量不足時,預設自增長度的一倍(如果不指定增量的話),如下原始碼可知
| | int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
| | capacityIncrement : oldCapacity);
|-----Set 元素唯一(最多包含一個 null 元素),只能通過遊標來取值,執行緒不安全
HashSet比TreeSet高效(尤其是查詢、新增),LinkedHashSet比hash插入、刪除慢,但是遍歷快。
|--|--HashSet 底層是由HashMap實現的,執行緒非安全,通過物件的hashCode方法與equals方法來保證插入元素的唯一性,無序(儲存順序和取出順序不一致)
|--|--|--LinkedHashSet 底層資料結構由雜湊表和連結串列組成。雜湊表保證元素的唯一性,連結串列保證元素有序。(儲存和取出是一致)
|--|--TreeSet 基於 TreeMap 的 NavigableSet 實現。非同步,排序,元素唯一。 保持有序的set使用(使用元素的自然順序對元素進行排序,或者根據建立 set 時提供的 Comparator 進行排序(紅黑數維護次序)
Map 是鍵值對集合,key 不允許重複,value 可以
|-----HashMap 基於連結串列和紅黑樹:hashMap用hash表實現的Map,就是利用物件的hashcode(hashcode()是Object的方法)進行快速雜湊查詢。Null可以做主鍵,但只能有一個
|-----TreeMap 基於紅黑樹
|-----LinkedHashMap HashMap+LinkedList
|-----HashTable 執行緒安全,不允許有null值的存在
java集合框架概括
只有Vector,HashTable是執行緒安全的
ArrayList,LinkedList,HashSet,TreeSet,HashMap,TreeMap都不是執行緒安全的。
如果沒有必要,推薦程式碼只同List,Map介面打交道.
HashMap的輸出順序是隨機的,TreeMap中的條目是按鍵值的升序排列的,LinkedHashMap是按元素最後一次被訪問的時間從早到晚排序的
簡明圖
Collection||Set泛型介面方法摘要
boolean add(E e) 確保此 collection 包含指定的元素(可選操作)。 boolean addAll(Collection c) 將指定 collection 中的所有元素都新增到此 collection 中(可選操作)。 void clear() 移除此 collection 中的所有元素(可選操作)。 boolean contains(Object o) 如果此 collection 包含指定的元素,則返回 true。 boolean containsAll(Collection c) 如果此 collection 包含指定 collection 中的所有元素,則返回 true。 boolean equals(Object o) 比較此 collection 與指定物件是否相等。 int hashCode() 返回此 collection 的雜湊碼值。 boolean isEmpty() 如果此 collection 不包含元素,則返回 true。 Iterator iterator() 返回在此 collection 的元素上進行迭代的迭代器。 boolean remove(Object o) 從此 collection 中移除指定元素的單個例項,如果存在的話(可選操作)。 boolean removeAll(Collection c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可選操作)。 boolean retainAll(Collection c) 僅保留此 collection 中那些也包含在指定 collection 的元素(可選操作)。 int size() 返回此 collection 中的元素數。 Object[] toArray() 返回包含此 collection 中所有元素的陣列。 T[] toArray(T[] a)
List泛型介面
特有方法(相對於Collection—繼承自Collection)
void add(int index, E element) 在列表的指定位置插入指定元素(可選操作)。 boolean addAll(int index, Collection c) 將指定 collection 中的所有元素都插入到列表中的指定位置(可選操作)。 int indexOf(Object o) 返回此列表中第一次出現的指定元素的索引;如果此列表不包含該元素,則返回 -1。 int lastIndexOf(Object o) 返回此列表中最後出現的指定元素的索引;如果列表不包含此元素,則返回 -1。 ListIterator listIterator() 返回此列表元素的列表迭代器(按適當順序)。 ListIterator listIterator(int index) 返回列表中元素的列表迭代器(按適當順序),從列表的指定位置開始。 E get(int index) 返回列表中指定位置的元素。 E remove(int index) 移除列表中指定位置的元素(可選操作)。 E set(int index, E element) 用指定元素替換列表中指定位置的元素(可選操作)。 List subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分檢視。
原文連結:https://www.zhoulujun.cn/html/java/javaBase/159.html 排版效果可能更好,本文若有不妥之處,請留言告知,拜謝!
參考文章:
java 集合詳解 https://www.cnblogs.com/ysocean/p/6555373.html
java集合詳解與基本使用方法 https://blog.csdn.net/qq_34232889/article/details/79997471
圖解Java常用資料結構 https://www.jianshu.com/p/fb4fb24ecc8f
java中的集合和陣列 https://www.cnblogs.com/summers/p/4094260.html
集合的執行緒安全性 https://www.cnblogs.com/wuchaodzxx/p/6007970.html
Set與執行緒安全 https://blog.csdn.net/l153097889/article/details/77891250
java常用資料結構及特點 https://blog.csdn.net/hujiangtaochn/article/details/84136432
Java集合框架之圖解 https://www.cnblogs.com/SamSarah/p/4893217.html
java.util包中集合詳解 https://www.jianshu.com/p/4bb01e139cda
使Cache命中率最高的替換演算法是什麼?替換最近最少使用的塊演