面试必问之ArrayList

  • 2019 年 10 月 3 日
  • 笔记

ArrayList??

?1?ArrayList ???????????????????

?2?ArrayList ???????????? ArrayList ???????????????????????????????????????

?3?ArrayList ????????????????? O(1) ?????????????

?4?ArrayList ?????????????????????? ArrayList???????????????

ArrayList?????

?????ArrayList????????????????????DEFAULTCAPACITY_EMPTY_ELEMENTDATA?EMPTY_ELEMENTDATA?????????????????????DEFAULTCAPACITY_EMPTY_ELEMENTDATA????????????

//???????  private static final int DEFAULT_CAPACITY = 10;    //???????????????????????????????  private static final Object[] EMPTY_ELEMENTDATA = {};    //????size??????????EMPTY_ELEMENTDATA?????  //????????????????????????  private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};    //ArrayList????????????????ArrayList??????????  //??????elementData????DEFAULTCAPACITY_EMPTY_ELEMENTDATA????????????  //???????????????????DEFAULT_CAPACITY  transient Object[] elementData; // non-private to simplify nested class access    //arrayList???  private int size;

static???EMPTY_ELEMENTDATA?DEFAULTCAPACITY_EMPTY_ELEMENTDATA

ArrayList????

?1?????????????

  • ????0?elementData????initialCapacity?????
  • ????0?elementData???????
  • ????0?????
//????????  public ArrayList(int initialCapacity) {      //????????      if (initialCapacity > 0) {          //elementData???????????          this.elementData = new Object[initialCapacity];      } else if (initialCapacity == 0) {          //????????0??????????????????(?????)          this.elementData = EMPTY_ELEMENTDATA;      } else {          throw new IllegalArgumentException("Illegal Capacity: "+                                             initialCapacity);      }  }

?2?????

  • ??????elementData???????DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  • ???add??????????????????
  • ??????DEFAULT_CAPACITY=10
//??????????size?10?????????????????????????????add?????????  public ArrayList() {      this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;  }

?3????Collection??????

//??????Collection??????ArrayList?????????????????????????  //??????null???????????c.toArray()??????  public ArrayList(Collection<? extends E> c) {      elementData = c.toArray();      if ((size = elementData.length) != 0) {          //c.toArray()??????????? Object[]???????Arrays.copyOf()??          if (elementData.getClass() != Object[].class)              elementData = Arrays.copyOf(elementData, size, Object[].class);      } else {          //????????????????0?????????????????elementData          this.elementData = EMPTY_ELEMENTDATA;      }  }

? ??????????????????????????????????????????? elementData(this.elementData=XXX)????????????? elementData ?????????????????????????????????????????? elementData ??????????>= 0????????????????????????????????? ArrayList ??????????????????????

? ??????????????????add????????????????????add?????????

ArrayList?add??

add??????

//????????list???  public boolean add(E e) {      //????????????????????????????????????????      ensureCapacityInternal(size + 1);  // Increments modCount!!???????fast-fail?      elementData[size++] = e;      return true;  }

????add???????????????size???????????ensureCapacityInternal?????

ensureCapacityInternal????

private void ensureCapacityInternal(int minCapacity) {      //??????elementData?????????      //????????????elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA?      //????????size+1(?????add???size+1=1)?DEFAULT_CAPACITY?      //???????10      if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {          minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);      }      ensureExplicitCapacity(minCapacity);  }

? ? ? add ??1?????minCapacity?(size+1=0+1=)1??Math.max()??????minCapacity ?10????????ensureExplicitCapacity??modCount????????????

ensureExplicitCapacity????

private void ensureExplicitCapacity(int minCapacity) {      modCount++; //????add??????Increments modCount      //??      if (minCapacity - elementData.length > 0)          grow(minCapacity);//???????????  }

? ?????????????grow?

grow????

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  private void grow(int minCapacity) {      // oldCapacity???????      int oldCapacity = elementData.length;      // newCapacity????????oldCap+oldCap/2:????????1.5??      int newCapacity = oldCapacity + (oldCapacity >> 1);      // ??????????????????????????????????????      if (newCapacity - minCapacity < 0)          newCapacity = minCapacity;      //???????MAX_ARRAY_SIZE???hugeCapacity????      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);  }

hugeCapacity??

???????hugeCapacity??

private static int hugeCapacity(int minCapacity) {      if (minCapacity < 0) // overflow          throw new OutOfMemoryError();      //?minCapacity?MAX_ARRAY_SIZE????      //?minCapacity???Integer.MAX_VALUE????????      //?MAX_ARRAY_SIZE???MAX_ARRAY_SIZE????????      //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;      return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;  }

add????????

? ???????????????????????????????add?????????

? ???????add??????????capacity?10???

  • ?????2?????????ensureCapacityInternal????????size+1=1+1=2?

  • ?ensureCapacityInternal????elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA??????????ensureExplicitCapacity??
  • ensureExplicitCapacity???minCapacity??????2??????if???2-10=-8???????newCapacity ?? MAX_ARRAY_SIZE??????? grow ????????10?add??? return true,size??1?
  • ?????3?4……10?????????????????grow?????
  • ?add?11?????????grow??????newCapacity?15??minCapacity??10+1=11??????if?????????????????size?????hugeCapacity?????????15?add???return true,size??11?

add(int index,E element)??

//????? index ?????  public void add(int index, E element) {      rangeCheckForAdd(index); //?????index???????      // 1. ????????      ensureCapacityInternal(size + 1);  // Increments modCount!!      // 2. ? index ???????????????      System.arraycopy(elementData, index, elementData, index + 1,                       size - index);      // 3. ??????? index ?      elementData[index] = element;      size++;  }  private void rangeCheckForAdd(int index) {      if (index > size || index < 0) //?????index>size???????????index??0          throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  }

add(int index, E element)??????????????????????????????????

  1. ????????????(?????????)
  2. ? index ??????????????
  3. ??????? index ?.

????????????????????????????????????????????????????????O(N)??????????????????????????????????????????????????????????????????

ArrayList?remove??

ArrayList???????????

1?remove(int index) ??????

public E remove(int index) {      rangeCheck(index); //???????????index>size????IndexOutOfBoundsException???      modCount++;//??list???????????      E oldValue = elementData(index); //???????????        int numMoved = size - index - 1;//????????????      //???????0 ???????????(size=index+1)      //???0????????????????(?????????)      if (numMoved > 0)          //??index???????????  ???index??????          System.arraycopy(elementData, index+1, elementData, index,                           numMoved);      //?????????size??null      elementData[--size] = null; // clear to let GC do its work      //????      return oldValue;  }  //src:???  //srcPos:?????srcPos???????  //dest:????  //desPos:????srcPos?????????????????????desPos?????  //length:????????  public static native void arraycopy(Object src,  int  srcPos,                                      Object dest, int destPos,                                      int length);

? ?????????

2?remove(Object o) ?????????????????????

public boolean remove(Object o) {      //?????null ?????????null      if (o == null) {          for (int index = 0; index < size; index++)              if (elementData[index] == null) {                  //???????null????? ???????????                  fastRemove(index);                  return true;              }      } else {          //????????? ???????????          for (int index = 0; index < size; index++)              if (o.equals(elementData[index])) {                  fastRemove(index);                  return true;              }      }      return false;  }  //?????????????????????????????  private void fastRemove(int index) {    modCount++;    int numMoved = size - index - 1;    if (numMoved > 0)      System.arraycopy(elementData, index+1, elementData, index,                       numMoved);    elementData[--size] = null; // clear to let GC do its work  }

ArrayList?????

ensureCapacity??

??? add ??????? ensureCapacity ???????????????

public void ensureCapacity(int minCapacity) {      int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)          // any size if not default element table          ? 0          // larger than default for default empty table. It's already          // supposed to be at default size.          : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {          ensureExplicitCapacity(minCapacity);      }  }

ArrayList??

?1?ArrayList ????????????????????????????????????10?1.7????????????????add???????????elementData??????10??

?2?ArrayList ???????????? ArrayList ???????????????????????????????????????ArrayList??????????1.5?

?3??? ArrayList ????????????????? O(1) ?????????????

?4?ArrayList ?????????????????????? ArrayList???????????????

?5????????

?6?????????????????????LinkindList?

?7?Integer.MAX_VALUE – 8 ??????????JVM,??JVM?????????,?????????MAX_ARRAY_SIZE,?????????????MAX_ARRAY_SIZE???,?????, ???Integer.MAX_VALUE,???Integer.MAX_VALUE -8? ????jdk1.7?????

fast-fail??

fail-fast????

In systems design, a fail-fast system is one which immediately reports at its interface any condition that is likely to indicate a failure. Fail-fast systems are usually designed to stop normal operation rather than attempt to continue a possibly flawed process. Such designs often check the system’s state at several points in an operation, so any failures can be detected early. The responsibility of a fail-fast module is detecting errors, then letting the next-highest level of the system handle them.

? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

? ????????????????????????????????????????????????

//?????????????????????fast_fail_method????????????????????????0????????????????????????????fail-fast????????  public int fast_fail_method(int arg1,int arg2){      if(arg2 == 0){          throw new RuntimeException("can't be zero");      }      return arg1/arg2;  }

? ?Java?????????????????????????????fail-fast????????????????????????Java??fail-fast????????Java??????????????????????????????????????????????????????????ConcurrentModificationException.????????????????foreach???????add/remove???????????????fast-fail???????????

? ??????ConcurrentModificationException?????????????????for???????for???????????iterator?????????add/remove????????????????????iterator??????????????????????????????/?????????????????????????????????Java????????????ConcurrentModificationException?????fail-fast????????????????????????Iterator???fail-fast????????????????????????????????????