2020最新阿里Java高級面試題(首發,50道附答案),你值得擁有~~~

1. Arraylist與LinkedList區別

可以從它們的底層數據結構、效率、開銷進行闡述哈

  • ArrayList是數組的數據結構,LinkedList是鏈表的數據結構。
  • 隨機訪問的時候,ArrayList的效率比較高,因爲LinkedList要移動指針,而ArrayList是基於索引(index)的數據結構,可以直接映射到。
  • 插入、刪除數據時,LinkedList的效率比較高,因爲ArrayList要移動數據。
  • LinkedList比ArrayList開銷更大,因爲LinkedList的節點除了存儲數據,還需要存儲引用。

2. Collections.sort和Arrays.sort的實現原理

Collection.sort是對list進行排序,Arrays.sort是對數組進行排序。

Collections.sort底層實現

Collections.sort方法調用了list.sort方法

2020最新阿里Java高級面試題(首發,50道附答案)

list.sort方法調用了Arrays.sort的方法

2020最新阿里Java高級面試題(首發,50道附答案)

因此,Collections.sort方法底層就是調用的Array.sort方法

Arrays.sort底層實現

Arrays的sort方法,如下:

2020最新阿里Java高級面試題(首發,50道附答案)

如果比較器爲null,進入sort(a)方法。如下:

2020最新阿里Java高級面試題(首發,50道附答案)

因此,Arrays的sort方法底層就是:

  • legacyMergeSort(a),歸併排序,
  • ComparableTimSort.sort():即Timsort排序。

Timesort排序

Timsort排序是結合了合併排序(merge.sort)和插入排序(insertion sort)而得出的排序方法;

1.當數組長度小於某個值,採用的是二分插入排序算法,如下:

2020最新阿里Java高級面試題(首發,50道附答案)

  1. 找到各個run,併入棧。

2020最新阿里Java高級面試題(首發,50道附答案)

 

  1. 按規則合併run。

2020最新阿里Java高級面試題(首發,50道附答案)

3. HashMap原理,java8做了什麼改變

  • HashMap是以鍵值對存儲數據的集合容器
  • HashMap是非線性安全的。
  • HashMap底層數據結構:數組+(鏈表、紅黑樹),jdk8之前是用數組+鏈表的方式實現,jdk8引進了紅黑樹
  • Hashmap數組的默認初始長度是16,key和value都允許null的存在
  • HashMap的內部實現數組是Node[]數組,上面存放的是key-value鍵值對的節點。HashMap通過put和get方法存儲和獲取。
  • HashMap的put方法,首先計算key的hashcode值,定位到對應的數組索引,然後再在該索引的單向鏈表上進行循環遍歷,用equals比較key是否存在,如果存在則用新的value覆蓋原值,如果沒有則向後追加。
  • jdk8中put方法:先判斷Hashmap是否爲空,爲空就擴容,不爲空計算出key的hash值i,然後看table[i]是否爲空,爲空就直接插入,不爲空判斷當前位置的key和table[i]是否相同,相同就覆蓋,不相同就查看table[i]是否是紅黑樹節點,如果是的話就用紅黑樹直接插入鍵值對,如果不是開始遍歷鏈表插入,如果遇到重複值就覆蓋,否則直接插入,如果鏈表長度大於8,轉爲紅黑樹結構,執行完成後看size是否大於閾值threshold,大於就擴容,否則直接結束。
  • Hashmap解決hash衝突,使用的是鏈地址法,即數組+鏈表的形式來解決。put執行首先判斷table[i]位置,如果爲空就直接插入,不爲空判斷和當前值是否相等,相等就覆蓋,如果不相等的話,判斷是否是紅黑樹節點,如果不是,就從table[i]位置開始遍歷鏈表,相等覆蓋,不相等插入。
  • HashMap的get方法就是計算出要獲取元素的hash值,去對應位置獲取即可。
  • HashMap的擴容機制,Hashmap的擴容中主要進行兩步,第一步把數組長度變爲原來的兩倍,第二步把舊數組的元素重新計算hash插入到新數組中,jdk8時,不用重新計算hash,只用看看原來的hash值新增的一位是零還是1,如果是1這個元素在新數組中的位置,是原數組的位置加原數組長度,如果是零就插入到原數組中。擴容過程第二部一個非常重要的方法是transfer方法,採用頭插法,把舊數組的元素插入到新數組中。
  • HashMap大小爲什麼是2的冪次方?效率高+空間分佈均勻

4. List 和 Set,Map 的區別

  • List 以索引來存取元素,有序的,元素是允許重複的,可以插入多個null。
  • Set 不能存放重複元素,無序的,只允許一個null
  • Map 保存鍵值對映射,映射關係可以一對一、多對一
  • List 有基於數組、鏈表實現兩種方式
  • Set、Map 容器有基於哈希存儲和紅黑樹兩種方式實現
  • Set 基於 Map 實現,Set 裏的元素值就是 Map的鍵值

5. poll()方法和 remove()方法的區別?

Queue隊列中,poll() 和 remove() 都是從隊列中取出一個元素,在隊列元素爲空的情況下,remove() 方法會拋出異常,poll() 方法只會返回 null 。

看一下源碼的解釋吧:

2020最新阿里Java高級面試題(首發,50道附答案)

6. HashMap,HashTable,ConcurrentHash的共同點和區別

HashMap

  • 底層由鏈表+數組+紅黑樹實現
  • 可以存儲null鍵和null值
  • 線性不安全
  • 初始容量爲16,擴容每次都是2的n次冪
  • 加載因子爲0.75,當Map中元素總數超過Entry數組的0.75,觸發擴容操作.
  • 併發情況下,HashMap進行put操作會引起死循環,導致CPU利用率接近100%
  • HashMap是對Map接口的實現

HashTable

  • HashTable的底層也是由鏈表+數組+紅黑樹實現。
  • 無論key還是value都不能爲null
  • 它是線性安全的,使用了synchronized關鍵字。
  • HashTable實現了Map接口和Dictionary抽象類
  • Hashtable初始容量爲11

ConcurrentHashMap

  • ConcurrentHashMap的底層是數組+鏈表+紅黑樹
  • 不能存儲null鍵和值
  • ConcurrentHashMap是線程安全的
  • ConcurrentHashMap使用鎖分段技術確保線性安全
  • JDK8爲何又放棄分段鎖,是因爲多個分段鎖浪費內存空間,競爭同一個鎖的概率非常小,分段鎖反而會造成效率低。

7. 寫一段代碼在遍歷 ArrayList 時移除一個元素

因爲foreach刪除會導致快速失敗問題,fori順序遍歷會導致重複元素沒刪除,所以正確解法如下:

第一種遍歷,倒敘遍歷刪除

for(int i=list.size()-1; i>-1; i--){
  if(list.get(i).equals("jay")){
    list.remove(list.get(i));
  }
}

第二種,迭代器刪除

Iterator itr = list.iterator();
while(itr.hasNext()) {
      if(itr.next().equals("jay") {
        itr.remove();
      }

8. Java中怎麼打印數組?

數組是不能直接打印的哈,如下:

public class Test {

    public static void main(String[] args) {
        String[] jayArray = {"jay", "boy"};
        System.out.println(jayArray);
    }
}
//output
[Ljava.lang.String;@1540e19d

打印數組可以用流的方式Strem.of().foreach(),如下:

public class Test {

    public static void main(String[] args) {
        String[] jayArray = {"jay", "boy"};
        Stream.of(jayArray).forEach(System.out::println);
    }
}
//output
jay
boy

打印數組,最優雅的方式可以用這個APi,Arrays.toString()

public class Test {
    public static void main(String[] args) {
        String[] jayArray = {"jay", "boy"};
        System.out.println(Arrays.toString(jayArray));
    }
}
//output
[jay, boy]

9. TreeMap底層?

  • TreeMap實現了SotredMap接口,它是有序的集合。
  • TreeMap底層數據結構是一個紅黑樹,每個key-value都作爲一個紅黑樹的節點。
  • 如果在調用TreeMap的構造函數時沒有指定比較器,則根據key執行自然排序。

2020最新阿里Java高級面試題(首發,50道附答案)

10. HashMap 的擴容過程

Hashmap的擴容:

  • 第一步把數組長度變爲原來的兩倍,
  • 第二步把舊數組的元素重新計算hash插入到新數組中。
  • jdk8時,不用重新計算hash,只用看看原來的hash值新增的一位是零還是1,如果是1這個元素在新數組中的位置,是原數組的位置加原數組長度,如果是零就插入到原數組中。擴容過程第二步一個非常重要的方法是transfer方法,採用頭插法,把舊數組的元素插入到新數組中。

11. HashSet是如何保證不重複的

可以看一下HashSet的add方法,元素E作爲HashMap的key,我們都知道HashMap的可以是不允許重複的,哈哈。

 public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

12. HashMap 是線程安全的嗎,爲什麼不是線程安全的?死循環問題?

不是線性安全的。

併發的情況下,擴容可能導致死循環問題。

13. LinkedHashMap的應用,底層,原理

  • LinkedHashMap維護着一個運行於所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可以是插入順序(insert-order)或者是訪問順序,其中默認的迭代訪問順序就是插入順序,即可以按插入的順序遍歷元素,這點和HashMap有很大的不同。
  • LRU算法可以用LinkedHashMap實現。

14. 哪些集合類是線程安全的?哪些不安全?

線性安全的

  • Vector:比Arraylist多了個同步化機制。
  • Hashtable:比Hashmap多了個線程安全。
  • ConcurrentHashMap:是一種高效但是線程安全的集合。
  • Stack:棧,也是線程安全的,繼承於Vector。

線性不安全的

  • Hashmap
  • Arraylist
  • LinkedList
  • HashSet
  • TreeSet
  • TreeMap

15. ArrayList 和 Vector 的區別是什麼?

  • Vector是線程安全的,ArrayList不是線程安全的。
  • ArrayList在底層數組不夠用時在原來的基礎上擴展0.5倍,Vector是擴展1倍。
  • Vector只要是關鍵性的操作,方法前面都加了synchronized關鍵字,來保證線程的安全性。

2020最新阿里Java高級面試題(首發,50道附答案)

16. Collection與Collections的區別是什麼?

  • Collection是Java集合框架中的基本接口,如List接口也是繼承於它
public interface List<E> extends Collection<E> {

Collections是Java集合框架提供的一個工具類,其中包含了大量用於操作或返回集合的靜態方法。如下:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

17. 如何決定使用 HashMap 還是TreeMap?

這個點,主要考察HashMap和TreeMap的區別。

TreeMap實現SortMap接口,能夠把它保存的記錄根據鍵排序,默認是按key的升序排序,也可以指定排序的比較器。當用Iterator遍歷TreeMap時,得到的記錄是排過序的。

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

List 轉 Array

List 轉Array,必須使用集合的 toArray(T[] array),如下:

List<String> list = new ArrayList<String>();
list.add("jay");
list.add("tianluo");

// 使用泛型,無需顯式類型轉換
String[] array = list.toArray(new String[list.size()]);
System.out.println(array[0]);

如果直接使用 toArray 無參方法,返回值只能是 Object[] 類,強轉其他類型可能有問題,demo如下:

List<String> list = new ArrayList<String>();
list.add("jay");
list.add("tianluo");

String[] array = (String[]) list.toArray();
System.out.println(array[0]);

運行結果:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at Test.main(Test.java:14)

Array 轉List

使用Arrays.asList() 把數組轉換成集合時,不能使用修改集合相關的方法啦,如下:

String[] str = new String[] { "jay", "tianluo" };
List list = Arrays.asList(str);
list.add("boy");

運行結果如下:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at Test.main(Test.java:13)

因爲 Arrays.asList不是返回java.util.ArrayList,而是一個內部類ArrayList。

2020最新阿里Java高級面試題(首發,50道附答案)

可以這樣使用彌補這個缺點:

//方式一:
ArrayList< String> arrayList = new ArrayList<String>(strArray.length);
Collections.addAll(arrayList, strArray);
//方式二:
ArrayList<String> list = new ArrayList<String>(Arrays.asList(strArray)) ;

19. 迭代器 Iterator 是什麼?怎麼用,有什麼特點?

public interface Collection<E> extends Iterable<E> {

Iterator<E> iterator();

方法如下:

next() 方法獲得集合中的下一個元素
hasNext() 檢查集合中是否還有元素
remove() 方法將迭代器新返回的元素刪除
forEachRemaining(Consumer<? super E> action) 方法,遍歷所有元素

Iterator 主要是用來遍歷集合用的,它的特點是更加安全,因爲它可以確保,在當前遍歷的集合元素被更改的時候,就會拋出 
ConcurrentModificationException 異常。

使用demo如下:

List<String> list = new ArrayList<>();
Iterator<String> it = list. iterator();
while(it. hasNext()){
  String obj = it. next();
  System. out. println(obj);
}

20. Iterator 和 ListIterator 有什麼區別?

2020最新阿里Java高級面試題(首發,50道附答案)

 

2020最新阿里Java高級面試題(首發,50道附答案)

 

  • ListIterator 比 Iterator有更多的方法。
  • ListIterator只能用於遍歷List及其子類,Iterator可用來遍歷所有集合,
  • ListIterator遍歷可以是逆向的,因爲有previous()和hasPrevious()方法,而Iterator不可以。
  • ListIterator有add()方法,可以向List添加對象,而Iterator卻不能。
  • ListIterator可以定位當前的索引位置,因爲有nextIndex()和previousIndex()方法,而Iterator不可以。
  • ListIterator可以實現對象的修改,set()方法可以實現。Iierator僅能遍歷,不能修改哦。

21. 怎麼確保一個集合不能被修改?

很多朋友很可能想到用final關鍵字進行修飾,final修飾的這個成員變量,如果是基本數據類型,表示這個變量的值是不可改變的,如果是引用類型,則表示這個引用的地址值是不能改變的,但是這個引用所指向的對象裏面的內容還是可以改變滴~驗證一下,如下:

public class Test {
    //final 修飾
    private static final Map<Integer, String> map = new HashMap<Integer, String>();
    {
        map.put(1, "jay");
        map.put(2, "tianluo");
    }

    public static void main(String[] args) {
        map.put(1, "boy");
        System.out.println(map.get(1));
    }
}

運行結果如下:

//可以洗髮現,final修飾,集合還是會被修改呢boy

嘻嘻,那麼,到底怎麼確保一個集合不能被修改呢,看以下這三哥們~

  • unmodifiableMap
  • unmodifiableList
  • unmodifiableSet

再看一下demo吧

public class Test {

    private static  Map<Integer, String> map = new HashMap<Integer, String>();
    {
        map.put(1, "jay");
        map.put(2, "tianluo");

    }

    public static void main(String[] args) {
        map = Collections.unmodifiableMap(map);
        map.put(1, "boy");
        System.out.println(map.get(1));
    }
}

運行結果:

// 可以發現,unmodifiableMap確保集合不能修改啦,拋異常了
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
	at Test.main(Test.java:14)

23. 什麼是Java優先級隊列(Priority Queue)?

優先隊列PriorityQueue是Queue接口的實現,可以對其中元素進行排序

  • 優先隊列中元素默認排列順序是升序排列
  • 但對於自己定義的類來說,需要自己定義比較器
public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {
    ...
     private final Comparator<? super E> comparator;

方法:

peek()//返回隊首元素
poll()//返回隊首元素,隊首元素出隊列
add()//添加元素
size()//返回隊列元素個數
isEmpty()//判斷隊列是否爲空,爲空返回true,不空返回false

特點:

  • 1.基於優先級堆
  • 2.不允許null值
  • 3.線程不安全
  • 4.出入隊時間複雜度O(log(n))
  • 5.調用remove()返回堆內最小值

24. JAVA8的ConcurrentHashMap爲什麼放棄了分段鎖,有什麼問題嗎,如果你來設計,你如何設計。

jdk8 放棄了分段鎖而是用了Node鎖,減低鎖的粒度,提高性能,並使用CAS操作來確保Node的一些操作的原子性,取代了鎖。

可以跟面試官聊聊悲觀鎖和CAS樂觀鎖的區別,優缺點哈~

25. 阻塞隊列的實現,ArrayBlockingQueue的底層實現?

ArrayBlockingQueue是數組實現的線程安全的有界的阻塞隊列,繼承自AbstractBlockingQueue,間接的實現了Queue接口和Collection接口。底層以數組的形式保存數據(實際上可看作一個循環數組)。常用的操作包括 add ,offer,put,remove,poll,take,peek。

2020最新阿里Java高級面試題(首發,50道附答案)

可以結合線程池跟面試官講一下哦~

26. Java 中的 LinkedList是單向鏈表還是雙向鏈表?

27. 說一說ArrayList 的擴容機制吧

28. HashMap 的長度爲什麼是2的冪次方,以及其他常量定義的含義~

29. ConcurrenHashMap 原理?1.8 中爲什麼要用紅黑樹?

30. ArrayList的默認大小

31. 爲何Collection不從Cloneable和Serializable接口繼承?

32. Enumeration和Iterator接口的區別?

33. 我們如何對一組對象進行排序?

34. 當一個集合被作爲參數傳遞給一個函數時,如何纔可以確保函數不能修改它?

35. 說一下HashSet的實現原理?

36. Array 和 ArrayList 有何區別?

37. 爲什麼HashMap中String、Integer這樣的包裝類適合作爲key?

38. 如果想用Object作爲hashMap的Key?

39. 講講紅黑樹的特點?

40. Java集合類框架的最佳實踐有哪些?

41.談談線程池阻塞隊列吧~

42. HashSet和TreeSet有什麼區別?

43. Set裏的元素是不能重複的,那麼用什麼方法來區分重複與否呢? 是用==還是equals()?

44. 說出ArrayList,LinkedList的存儲性能和特性

45. HashMap在JDK1.7和JDK1.8中有哪些不同?

46. ArrayList集合加入1萬條數據,應該怎麼提高效率

47. 如何對Object的list排序

48. ArrayList 和 HashMap 的默認大小是多數?

49. 有沒有有順序的Map實現類,如果有,他們是怎麼保證有序的

50. HashMap是怎麼解決哈希衝突的

資料部分截圖展現

架構學習視頻、源碼實戰文檔、java電子書籍、大廠面試資料等等

2020最新阿里Java高級面試題(首發,50道附答案)

java電子書部分截圖

2020最新阿里Java高級面試題(首發,50道附答案)

面試資料

2020最新阿里Java高級面試題(首發,50道附答案)

Redis學習視頻

2020最新阿里Java高級面試題(首發,50道附答案)

數據結構與算法視頻

2020最新阿里Java高級面試題(首發,50道附答案)

源碼解析文檔

2020最新阿里Java高級面試題(首發,50道附答案)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章