Java核心技術及面試指南 線性表方面的面試題總結以及答案


3.2.7.1 請用ArrayList實現Stack以及Queue的功能。

 
public class ArrayListStack extends ArrayList implements Stack {
    ArrayList arrayList =new ArrayList<>() ;
    public void push(T obj) {
       arrayList.add(obj);
    }
    public T pop() {
        return arrayList.remove(arrayList.size()-1);
    }

    public int size(){

        return arrayList.size(); 

    }
}

3.2.7.2 如果讓你實現Java的ArrayList,你需要考慮哪些要素?

    ArrayList是基於數組實現的,是一個動態數組,其容量能自動增長,類似於C語言中的動態申請內存,動態增長內存。 

    ArrayList實現了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現了RandomAccess接口,支持快速隨機訪問,實際上就是通過下標序號進行快速訪問,實現了Cloneable接口,能被克隆。

   每個ArrayList實例都有一個容量,該容量是指用來存儲列表元素的數組的大小。它總是至少等於列表的大小。隨着向ArrayList中不斷添加元素,其容量也自動增長。自動增長會帶來數據向新數組的重新拷貝,因此,如果可預知數據量的多少,可在構造ArrayList時指定其容量。在添加大量元素前,應用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數量。 
   注意,此實現不是同步的。如果多個線程同時訪問一個ArrayList實例,而其中至少一個線程從結構上修改了列表,那么它必須保持外部同步。

     ArrayList提供了三種方式的構造器,可以構造一個默認初始容量為10的空列表、構造一個指定初始容量的空列表以及構造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回它們的順序排列的。

    ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)這些添加元素的方法。

    每當向數組中添加元素時,都要去檢查添加后元素的個數是否會超出當前數組的長度,如果超出,數組將會進行擴容,以滿足添加數據的需求。數組擴容通過一個公開的方法ensureCapacity(int minCapacity)來實現。在實際添加大量元素前,我也可以使用ensureCapacity來手動增加ArrayList實例的容量,以減少遞增式再分配的數量。

    數組進行擴容時,會將老數組中的元素重新拷貝一份到新的數組中,每次數組容量的增長大約是其原容量的1.5倍。這種操作的代價是很高的,因此在實際使用時,我們應該盡量避免數組容量的擴張。當我們可預知要保存的元素的多少時,要在構造ArrayList實例時,就指定其容量,以避免數組擴容的發生。或者根據實際需求,通過調用ensureCapacity方法來手動增加ArrayList實例的容量。 

    Fail-Fast機制: 
ArrayList也采用了快速失敗的機制,通過記錄modCount參數來實現。在面對並發的修改時,迭代器很快就會完全失敗,而不是冒着在將來某個不確定時間發生任意不確定行為的風險。

 

3.2.7.3 請通過Iterator對象訪問LinkedList對象,並說明這種訪問方式的好處。

  LinkedList  list =  new LinkedList();

  //省略賦值
  ListIterator it = list.listIterator();
  while(it.hasNext()) { 
   System.out.println(it.next().toString()); //使用  
  }

  好處是,能用統一的方式來訪問集合對象,這也是迭代器模式的好處。

 

3.2.7.4 你有沒有讀過ArrayList部分的底層實現源代碼?如果有,請說明下其中的add方法是如何實現的?尤其請考慮動態擴展的情況。

如下是擴容的底層方法

/**
* 增加ArrayList容量。
*
* @param minCapacity 想要的最小容量
*/
public void ensureCapacity(int minCapacity) {
    // 如果elementData等於DEFAULTCAPACITY_EMPTY_ELEMENTDATA,最小擴容量為DEFAULT_CAPACITY,否則為0
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
    //如果想要的最小容量大於最小擴容量,則使用想要的最小容量。
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}
/**
* 數組容量檢查,不夠時則進行擴容,只供類內部使用。
*
* @param minCapacity 想要的最小容量
*/
private void ensureCapacityInternal(int minCapacity) {
    // 若elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,則取minCapacity為DEFAULT_CAPACITY和參數minCapacity    之間的最大值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}
/**
* 數組容量檢查,不夠時則進行擴容,只供類內部使用
*
* @param minCapacity 想要的最小容量
*/
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // 確保指定的最小容量 > 數組緩沖區當前的長度
    if (minCapacity - elementData.length > 0)
    //擴容
    grow(minCapacity);
}

/**
* 分派給arrays的最大容量
* 為什么要減去8呢?
* 因為某些VM會在數組中保留一些頭字,嘗試分配這個最大存儲容量,可能會導致array容量大於VM的limit,最終導致OutOfMemoryError。
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
* 擴容,保證ArrayList至少能存儲minCapacity個元素
* 第一次擴容,邏輯為newCapacity = oldCapacity + (oldCapacity >> 1);即在原有的容量基礎上增加一半。第一次擴容后,如果容量還是小於minCapacity,就將容量擴充為minCapacity。
*
* @param minCapacity 想要的最小容量
*/
private void grow(int minCapacity) {
    // 獲取當前數組的容量
    int oldCapacity = elementData.length;
    // 擴容。新的容量=當前容量+當前容量/2.即將當前容量增加一半。
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果擴容后的容量還是小於想要的最小容量
    if (newCapacity - minCapacity < 0)
        //將擴容后的容量再次擴容為想要的最小容量
        newCapacity = minCapacity;
    //如果擴容后的容量大於臨界值,則進行大容量分配
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
     // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData,newCapacity);
}
/**
* 進行大容量分配
*/
private static int hugeCapacity(int minCapacity) {
    //如果minCapacity<0,拋出異常
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    //如果想要的容量大於MAX_ARRAY_SIZE,則分配Integer.MAX_VALUE,否則分配MAX_ARRAY_SIZE
    return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}

 

3.2.7.5 請說下Collection和Collections的差別以及各自的用途。

    Collections 是一個集合的一個類,其中包含有一些和集合操作相關的靜態多態方法。Jave集合里則有另外一個和它非常相似的接口    

    Collection(不帶s),它是線性表類集合的父接口,List和Set等接口都是通過實現這個接口來實現的。

 

3.2.7.6 我們知道Set對象里不能有重復的元素,請說下是用什么方法來判斷是否重復?是通過equals方法嗎?

    請參與本書3.2.3 Set集合是如何判斷重復,里面有詳細的描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM