Java 容器

一、Java集合類框架的基本接口有哪些?二、Collection 和 Collections 有什麼區別?三、爲何集合類接口沒有實現 Cloneable 和 Serializable 接口?四、List、Set、Map 之間的區別是什麼?五、什麼是迭代器(Iterator)?六、Iterator 和 ListIterator 的區別是什麼?七、快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什麼?八、HashMap 和 Hashtable 有什麼區別?九、ConcurrentHashMap 和 Hashtable 的區別十、ConcurrentHashMap 線程安全的具體實現方式/底層具體實現十一、Java 中的 HashMap 的工做原理是什麼?十二、hashmap 大小爲何是 2 的冪次方1三、hashCode()和 equals()方法的重要性體如今什麼地方?1四、數組(Array)和列表(ArrayList)有什麼區別?何時應該使用 Array 而不是 ArrayList?1五、ArrayList 和 LinkedList 有什麼區別?1六、Comparable 和 Comparator 接口是幹什麼的?列出它們的區別。1七、什麼是 Java 優先級隊列(Priority Queue)?1八、Java集合類框架的最佳實踐有哪些?1九、HashSet 和 TreeSet 有什麼區別?20、HashSet 的實現原理?如何實現數組和 List 之間的轉換?2一、Arrays.asList()使用指南Collection.toArray()方法使用的坑&如何反轉數組2二、ArrayList 和 Vector 的區別是什麼?2三、在 Queue 中 poll()和 remove()有什麼區別?php

一、Java集合類框架的基本接口有哪些?

總共有兩大接口:Collection 和 Map ,一個元素集合,一個是鍵值對集合; 其中 List 和 Set 接口繼承了 Collection 接口,一個是有序元素集合,一個是無序元素集合; 而 ArrayList 和 LinkedList 實現了 List 接口,HashSet 實現了 Set 接口,這幾個都比較經常使用; HashMap 和 HashTable 實現了 Map 接口,而且 HashTable 是線程安全的,可是 HashMap 性能更好;html

二、Collection 和 Collections 有什麼區別?

  • java.util.Collection 是一個集合接口(集合類的一個頂級接口)。它提供了對集合對象進行基本操做的通用接口方法。Collection 接口在 Java 類庫中有不少具體的實現。Collection 接口的意義是爲各類具體的集合提供了最大化的統一操做方式,其直接繼承接口有 List 與 Set。java

  • Collections 則是集合類的一個工具類/幫助類,其中提供了一系列靜態方法,用於對集合中元素進行排序、搜索以及線程安全等各類操做。git

三、爲何集合類接口沒有實現 Cloneable 和 Serializable 接口?

克隆(cloning)或者是序列化(serialization)的語義和含義是跟具體的實現相關的。所以,應該由集合類的具體實現來決定如何被克隆或者是序列化。github

四、List、Set、Map 之間的區別是什麼?

五、什麼是迭代器(Iterator)?

迭代器是一種設計模式,它是一個對象,它能夠遍歷並選擇序列中的對象,而開發人員不須要了解該序列的底層結構。迭代器一般被稱爲「輕量級」對象,由於建立它的代價小。web

  Java 中的 Iterator 功能比較簡單,而且只能單向移動:設計模式

  (1) 使用方法 iterator()要求容器返回一個 Iterator。第一次調用 Iterator 的 next()方法時,它返回序列的第一個元素。注意:iterator()方法是 java.lang.Iterable 接口,被 Collection 繼承。數組

  (2) 使用 next()得到序列中的下一個元素。安全

  (3) 使用 hasNext()檢查序列中是否還有元素。數據結構

  (4) 使用 remove()將迭代器新返回的元素刪除。

  Iterator 是 Java 迭代器最簡單的實現,爲 List 設計的 ListIterator 具備更多的功能,它能夠從兩個方向遍歷 List,也能夠從 List 中插入和刪除元素。

六、Iterator 和 ListIterator 的區別是什麼?

Iterator 可用來遍歷 Set 和 List 集合,可是 ListIterator 只能用來遍歷 List。
Iterator 對集合只能是前向遍歷,ListIterator 既能夠前向也能夠後向。
ListIterator 實現了 Iterator 接口,幷包含其餘的功能,好比:增長元素,替換元素,獲取前一個和後一個元素的索引等等。

七、快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什麼?

快速失敗:當你在迭代一個集合的時候,若是有另外一個線程正在修改你正在訪問的那個集合時,就會拋出一個 ConcurrentModification 異常。
在 java.util 包下的都是快速失敗,不能在多線程下發生併發修改(迭代過程當中被修改)。

安全失敗:你在迭代的時候會去底層集合作一個拷貝,因此你在修改上層集合的時候是不會受影響的,不會拋出 ConcurrentModification 異常。
在 java.util.concurrent 包下的全是安全失敗的。能夠在多線程下併發使用,併發修改。

八、HashMap 和 Hashtable 有什麼區別?

一、HashMap 是非線程安全的,HashTable 是線程安全的。

二、HashMap 的鍵和值都容許有 null 值存在,而 HashTable 則不行。

三、由於線程安全的問題,HashMap 效率比 HashTable 的要高。

四、Hashtable 是同步的,而 HashMap 不是。所以,HashMap 更適合於單線程環境,而 Hashtable 適合於多線程環境。

五、二者提供了可供應用迭代的鍵的集合,都是快速失敗的。此外 Hashtable 提供了對鍵的列舉(Enumeration)

六、初始容量大小和每次擴充容量大小的不一樣: ①建立時若是不指定容量初始值,Hashtable 默認的初始大小爲 11,以後每次擴充,容量變爲原來的 2n+1。HashMap 默認的初始化大小爲 16。以後每次擴充,容量變爲原來的 2 倍。②建立時若是給定了容量初始值,那麼 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充爲 2 的冪次方大小(HashMap 中的 tableSizeFor()方法保證,下面給出了源代碼)。也就是說 HashMap 老是使用 2 的冪做爲哈希表的大小。

通常如今不建議用 HashTable, ①是 HashTable 是遺留類,內部實現不少沒優化和冗餘。②即便在多線程環境下,如今也有同步的 ConcurrentHashMap 替代,沒有必要由於是多線程而用 HashTable。

HashMap 中帶有初始容量的構造函數:

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
     public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
複製代碼

下面這個方法保證了 HashMap 老是使用2的冪做爲哈希表的大小。

    /**
     * Returns a power of two size for the given target capacity.
     */

    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
複製代碼

九、ConcurrentHashMap 和 Hashtable 的區別

  • 底層數據結構:ConcurrentHashMap 在 JDK1.7 底層採用 分段的數組+鏈表 實現,在 JDK1.8 採用的數據結構跟 HashMap1.8 的結構同樣,數組+鏈表/紅黑二叉樹。Hashtable 和 JDK1.8 以前的 HashMap 的底層數據結構相似都是採用 數組+鏈表 的形式,數組是 HashMap 的主體,鏈表則是主要爲了解決哈希衝突而存在的;
  • 實現線程安全的方式: ① 在 JDK1.7 的時候,ConcurrentHashMap(分段鎖) 對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器裏不一樣數據段的數據,就不會存在鎖競爭,提升併發訪問率。 到了 JDK1.8 的時候已經摒棄了 Segment 的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,併發控制使用 synchronized 和 CAS 來操做。(JDK1.6之後 對 synchronized鎖作了不少優化) 整個看起來就像是優化過且線程安全的 HashMap,雖然在 JDK1.8 中還能看到 Segment 的數據結構,可是已經簡化了屬性,只是爲了兼容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全,效率很是低下。當一個線程訪問同步方法時,其餘線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另外一個線程不能使用 put 添加元素,也不能使用 get,競爭會愈來愈激烈效率越低。

二者的對比圖:

圖片來源:http://www.cnblogs.com/chengxiao/p/6842045.html

HashTable:

JDK1.7 的 ConcurrentHashMap:


JDK1.8 的 ConcurrentHashMap(TreeBin: 紅黑二叉樹節點 Node: 鏈表節點):

十、ConcurrentHashMap 線程安全的具體實現方式/底層具體實現

JDK1.7(上面有示意圖)

首先將數據分爲一段一段的存儲,而後給每一段數據配一把鎖,當一個線程訪問其中一個段數據時,只是佔用當前數據段的鎖,其餘段的數據也能被其餘線程訪問。

ConcurrentHashMap 是由 Segment 數組結構和 HashEntry 數組結構組成。

Segment 實現了 ReentrantLock,因此 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用於存儲鍵值對數據。

static class Segment<K,Vextends ReentrantLock implements Serializable {
}
複製代碼

一個 ConcurrentHashMap 裏包含一個 Segment 數組。Segment 的結構和 HashMap 相似,是一種數組和鏈表結構,一個 Segment 包含一個 HashEntry 數組,每一個 HashEntry 是一個鏈表結構的元素,每一個 Segment 守護着一個HashEntry數組裏的元素,當對 HashEntry 數組的數據進行修改時,必須首先得到對應的 Segment的鎖。

JDK1.8 (上面有示意圖)

ConcurrentHashMap 取消了Segment 分段鎖,採用 CAS 和 synchronized 來保證併發安全。數據結構跟 HashMap1.8 的結構相似,數組+鏈表/紅黑二叉樹。Java 8 在鏈表長度超過必定閾值(8)時將鏈表(尋址時間複雜度爲O(N))轉換爲紅黑樹(尋址時間複雜度爲 O(log(N)))

synchronized 只鎖定當前鏈表或紅黑二叉樹的首節點,這樣只要 hash 不衝突,就不會產生併發,效率又提高 N 倍。

推薦閱讀:

十一、Java 中的 HashMap 的工做原理是什麼?

hashmap 是一個 key-value 鍵值對的數據結構,從結構上來說在 jdk1.8 以前是用數組加鏈表的方式實現,jdk1.8 加了紅黑樹,hashmap 數組的默認初始長度是 16,hashmap 數組只容許一個 key 爲 null,容許多個 value 爲 null。

hashmap 的內部實現,hashmap 是使用數組+鏈表+紅黑樹的形式實現的,其中數組是一個一個 Node[]數組,咱們叫他 hash 桶數組,它上面存放的是 key-value 鍵值對的節點。HashMap 是用 hash 表來存儲的,在 hashmap 裏爲解決 hash 衝突,使用鏈地址法,簡單來講就是數組加鏈表的形式來解決,當數據被 hash 後,獲得數組下標,把數據放在對應下標的鏈表中。

而後再說一下 hashmap 的方法實現

  • put 方法,put 方法的第一步,就是計算出要 put 元素在 hash 桶數組中的索引位置,獲得索引位置須要三步,計算要 put 元素 key 的 hashcode 值,高位運算,取模運算,高位運算就是用第一步獲得的值 h,用 h 的高 16 位和低 16 位進行異或操做,第三步爲了使 hash 桶數組元素分佈更均勻,採用取模運算,取模運算就是用第二步獲得的值和 hash 桶數組長度-1的值取與。這樣獲得的結果和傳統取模運算結果一致,並且效率比取模運算高。

  • jdk1.8 中 put 方法的具體步驟,先判斷 hashmap 是否爲空,爲空的話擴容,不爲空計算出 key 的 索引值 i,而後看 table[i]是否爲空,爲空就直接插入,不爲空判斷當前位置的 key 和 table[i] 是否相同,相同就覆蓋,不相同就查看 table[i] 是不是紅黑樹節點,若是是的話就用紅黑樹直接插入鍵值對,若是不是開始遍歷鏈表插入,若是遇到重複值就覆蓋,不然直接插入,若是鏈表長度大於 8,轉爲紅黑樹結構,執行完成後看 size 是否大於閾值 threshold,大於就擴容,不然直接結束。

  • get 方法就是計算出要獲取元素的 hash 值,去對應位置取便可。

HashMap 的兩個重要屬性是容量 capacity 和加載因子 loadfactor,默認值分佈爲 16 和 0.75,當容器中的元素個數大於 capacity*loadfactor 時,容器會進行擴容 resize 爲 2n,在初始化 Hashmap 時能夠對着兩個值進行修改,負載因子 0.75 被證實爲是性能比較好的取值,一般不會修改,那麼只有初始容量 capacity 會致使頻繁的擴容行爲,這是很是耗費資源的操做,因此,若是事先能估算出容器所要存儲的元素數量,最好在初始化時修改默認容量 capacity,以防止頻繁的 resize 操做影響性能。

擴容機制,hashmap 的擴容中主要進行兩步,第一步把數組長度變爲原來的兩倍,第二部把舊數組的元素從新計算 hash 插入到新數組中,在 jdk1.8 時,不用從新計算 hash,只用看看原來的 hash 值新增的一位是零仍是 1,若是是 1, 這個元素在新數組中的位置,是原數組的位置加原數組長度,若是是零就插入到原數組中。擴容過程第二步一個很是重要的方法是 transfer 方法,採用頭插法,把舊數組的元素插入到新數組中。

十二、hashmap 大小爲何是 2 的冪次方

在計算插入元素在 hash 桶數組的索引時第三步,爲了使元素分佈的更加均勻,用取模操做,可是傳統取模操做效率低,而後優化成 h&(length-1),設置成 2 冪次方,是由於 2 的冪次方-1後的值每一位上都是 1,而後與第二步計算出的 h 值與的時候,最終的結果只和 key 的 hashcode 值自己有關,這樣不會形成空間浪費而且分佈均勻。
若是 length 不爲 2 的冪,好比 15。那麼 length-1 的 2 進制就會變成 1110。在 h 爲隨機數的狀況下,和 1110 作&操做。尾數永遠爲 0。那麼 000一、100一、1101 等尾數爲 1 的位置就永遠不可能被 entry 佔用。這樣會形成浪費,不隨機等問題。

1三、hashCode()和 equals()方法的重要性體如今什麼地方?

HashMap 的不少函數要基於 equal()函數和 hashCode()函數。hashCode()用來定位要存放的位置,equal()用來判斷是否相等。hashcode 和 equals 組合在一塊兒肯定元素的惟一性。

查找元素時,若是單單使用 equals 來肯定一個元素,須要對集合內的元素逐個調用 equals 方法,效率過低。所以加入了 hashcode 方法,將元素映射到隨機的內存地址上,經過 hashcode 快速定位到元素(大體)所在的內存地址,再經過使用 equals 方法肯定元素的精確位置。
比較兩個元素時,先比較 hashcode,若是 hashcode 不一樣,則元素必定不相等;若是相同,再用 equals 判斷。

HashMap 採用這兩個方法實現散列存儲,提升鍵的索引性能。HashSet 是基於 HashMap 實現的

1四、數組(Array)和列表(ArrayList)有什麼區別?何時應該使用 Array 而不是 ArrayList?

  • 數組能夠包含基本數據類型和引用類型,ArrayList 只能包含引用類型。注意:Array 數組在存放的時候必定是同種類型的元素。ArrayList 就不必定了,由於 ArrayList 能夠存儲 Object。
  • 數組空間大小是固定的,但 ArrayList 空間大小是動態變化的,初始化的時候沒有定義它的默認容量大小,那麼默認是 10,以後的增加規則是:((舊容量 * 3) / 2) + 1
  • ArrayList 是 List 接口的實現類,相比數組支持更多的方法和特性。

適用場景:

  • 當集合長度固定時,使用數組;當集合的長度不固定時,使用 ArrayList。

  • 因爲 ArrayList 不支持基本數據類型,因此保存基本數據類型時須要裝箱處理,對比數組性能會降低。這種狀況儘可能使用數組。

  • 數組支持的操做方法不多,但內存佔用少,若是隻需對集合進行隨機讀寫,選數組

1五、ArrayList 和 LinkedList 有什麼區別?

ArrayList 和 LinkedList 都實現了 List 接口,他們有如下的不一樣點:

ArrayList 是基於索引的數據接口,它的底層是數組。它能夠以O(1)時間複雜度對元素進行隨機訪問,適合元素查找。與此對應,LinkedList 基於鏈表,爲雙向鏈表(JDK1.6 以前爲循環鏈表,JDK1.7 取消了循環), 每個元素都和它的前一個和後一個元素連接在一塊兒,在這種狀況下,查找某個元素的時間複雜度是 O(n)。

相對於 ArrayList,LinkedList 增刪操做速度更快,由於當元素被添加到集合任意位置的時候,不須要像數組那樣從新計算大小或者是更新索引。

LinkedList 比 ArrayList 更佔內存,由於 LinkedList 爲每個節點存儲了兩個引用,一個指向前一個元素,一個指向後一個元素。

1六、Comparable 和 Comparator 接口是幹什麼的?列出它們的區別。

Comparable & Comparator 都是用來實現集合中元素的比較、排序的。

Comparable 接口(內部比較器):

  • Comparable 位於 java.lang 包下。
  • comparable 接口是在內部類經過重寫 compareTo 方法實現的。在使用 Collections.sort(List list)或者Array.sort(Object[] a)對對象集合進行排序的時候,就會根據對象自定義的排序方法排序。
  • comparable 接口實現較簡單,但對於多元素排序不方便,由於在重寫 compareTo 方法時事先定義好了元素比較順序
  • 使用 Comparable 方式比較時,咱們將比較的規則寫入了比較的類型中,其特色是高內聚。但若是哪天這個規則須要修改,那麼咱們必須修改這個類型的源代碼。

Comparator 接口(外部比較器):

  • Comparator 位於 java.util 包下。
  • comparator 接口則是在外部類經過重寫 compare 與 equals 方法實現的。
  • comparator 接口實現較複雜,可能定義多個外部類,但對於多元素比較使用起來很方便。
  • 使用 Comparator 方式比較,那麼咱們不須要修改比較的類,其特色是易維護,但須要自定義一個比較器,後續比較規則的修改,僅僅是改這個比較器中的代碼便可。

1七、什麼是 Java 優先級隊列(Priority Queue)?

PriorityQueue 的邏輯結構是一棵徹底二叉樹,存儲結構實際上是一個數組。邏輯結構層次遍歷的結果恰好是一個數組。

PriorityQueue 是一個基於優先級堆的無界隊列,它的元素是按照天然順序(natural order)排序的。在建立的時候,咱們能夠給它提供一個負責給元素排序的比較器。PriorityQueue 不容許 null 值,由於他們沒有天然順序,或者說他們沒有任何相關聯的比較器。最後,PriorityQueue 不是線程安全的,入隊和出隊的時間複雜度是 O(log(n))。

1八、Java集合類框架的最佳實踐有哪些?

1九、HashSet 和 TreeSet 有什麼區別?

Hashset 的底層是由哈希表實現的,Hashset 中的元素是無序的。add(),remove(),contains()方法的時間複雜度是 O(1)。

Treeset 底層是由紅黑樹實現的。若是須要在 Treeset 中插入對象,須要實現 Comparable 接口,重寫 compareTo 方法。

20、HashSet 的實現原理?

  • HashSet 底層由 HashMap 實現

  • HashSet 的值存放於 HashMap 的 key 上

  • HashMap 的 value 統一爲 PRESENT

如何實現數組和 List 之間的轉換?

List 轉換成爲數組:調用 ArrayList 的 toArray 方法。

數組轉換成爲 List:調用 Arrays 的 asList 方法。

2一、Arrays.asList()使用指南

String[] myArray = { "Apple""Banana""Orange" }; 
List<String> myList = Arrays.asList(myArray);
//上面兩個語句等價於下面一條語句
List<String> myList = Arrays.asList("Apple","Banana""Orange");
複製代碼

注意:使用工具類 Arrays.asList()把數組轉換爲集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。
說明:asList 的返回對象是一個 Arrays 內部類,並無實現集合的修改方法。Arrays.asList 體現的是適配器模式,只是轉換接口,後臺的數據還是數組。

String[] str = new String[]{"and","you"};
List list = Arrays.asList(str);
System.out.println(list.get(1));//輸出you
list.add("yes");//拋出異常
str[0] = s"yes";
System.out.println(list);//list也會發生改變,輸出[yes, you]
複製代碼

Arrays.asList()是泛型方法,傳入的參數對象必須是對象數組。

int[] myArray = { 123 };
List myList = Arrays.asList(myArray);
System.out.println(myList.size());//1
System.out.println(myList.get(0));//數組地址值
System.out.println(myList.get(1));//報錯:ArrayIndexOutOfBoundsException
int [] array=(int[]) myList.get(0);
System.out.println(array[1]);//1
複製代碼

當傳入一個原生數據類型數組時,Arrays.asList() 的真正獲得的參數就不是數組中的元素,而是數組對象自己!此時List 的惟一元素就是這個數組,這也就解釋了上面的代碼。

轉換爲包裝數據類型便可。

Integer[] myArray = { 123 };
List myList = Arrays.asList(myArray);
System.out.println(myList.size());//數組長度3
System.out.println(myList.get(0));//1
System.out.println(myList.get(1));//2
複製代碼

使用集合的修改方法:add()、remove()、clear()會拋出異常。

Arrays.asList() 方法返回的並非 java.util.ArrayList ,而是 java.util.Arrays 的一個內部類,這個內部類並無實現集合的修改方法或者說並無重寫這些方法。

List myList = Arrays.asList(123);
System.out.println(myList.getClass());//class java.util.Arrays$ArrayList
複製代碼

如何正確的將數組轉換爲ArrayList?

一、自定義代碼

static <T> List<T> arraysToList(T[] array){
    List<T> list = new ArrayList<T>(array.length);

    for(T obj:array){
        list.add(obj);
    }
    return list;
}

String[] str = new String[]{"and","you"};
List ll = arraysToList(str);
System.out.println(ll.getClass());//class java.util.ArrayList

int[] myArray = { 123 };
List ll2 = arraysToList(myArray);//編譯報錯
複製代碼

該方法暫不支持基本數據類型。

二、最簡便的方法(推薦)

List list = new ArrayList<>(Arrays.asList("a""b""c"))
複製代碼

三、使用 Java8 的 Stream(推薦)

Integer [] myArray = { 123 };
List myList = Arrays.stream(myArray).collect(Collectors.toList());
//基本類型也能夠實現轉換(依賴boxed的裝箱操做)
int [] myArray2 = { 123 };
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());
複製代碼

四、 使用 Guava(推薦)

對於可變集合,你可使用 Lists 類及其 newArrayList()工廠方法:

String[] str = {"acd","yes"};
List list = Lists.newArrayList(str);//class java.util.ArrayList

int[] myArray = { 123 };
list = Lists.newArrayList(myArray);//class java.util.ArrayList
複製代碼

五、使用 Apache Commons Collections

List<String> list = new ArrayList<String>();
CollectionUtils.addAll(list, str);
複製代碼

Collection.toArray()方法使用的坑&如何反轉數組

該方法是一個泛型方法: T[] toArray(T[] a); 若是 toArray 方法中沒有傳遞任何參數的話返回的是 Object 類型數組。

String [] s= new String[]{
    "dog""lazy""a""over""jumps""fox""brown""quick""A"
};
List<String> list = Arrays.asList(s);//class java.util.Arrays$ArrayList
Collections.reverse(list);
s=list.toArray(new String[0]);//沒有指定類型的話會報錯,s2類型爲String
Object[] s2 = list.toArray();//效果同上

list = Lists.newArrayList(s);//class java.util.ArrayList
Collections.reverse(list);
s = list.toArray(new String[0]);//編譯報錯
Object[] s2 = list.toArray(new String[0]);//s2類型爲String
複製代碼

綜上可知,當數組爲引用類型數組時,使用 Arrays.asList 轉換爲 List,反轉操做後,再轉換爲數組,不管 toArray()方法中是否有參數,聲明爲 Object 類型的數組實際類型都爲原引用類型。使用其餘數組轉 List 方法,好比 Lists.newArrayList,須要在 toArray()參數中傳入對應類型,最後獲得的數組類型也是原類型。

當數組爲基本數據數組時,最後轉換以後獲得的數組爲 Object 類型。

2二、ArrayList 和 Vector 的區別是什麼?

  • Vector 是線程安全的,ArrayList 不是線程安全的。
  • ArrayList 在底層數組不夠用時在原來的基礎上擴展 0.5 倍,Vector 是擴展 1 倍。
  • ArrayList 更加通用,由於線程安全須要更大的系統開銷。

2三、在 Queue 中 poll()和 remove()有什麼區別?

poll() 和 remove() 都是從隊列中取出一個元素,可是 poll() 在獲取元素失敗的時候會返回空,可是 remove() 失敗的時候會拋出異常。

相關文章
相關標籤/搜索