Java ArrayList 학습 노트

21057 단어 Java
머리말
최근 에 저 는 자바 기 초 를 공부 하고 있 는데 자주 사용 하 는 Array List 가 중요 하 다 는 것 을 알 게 되 었 습 니 다.그래서 찾 아 볼 수 있 도록 필 기 를 했 습 니 다.필 기 는 많은 선배 들 의 글(링크 첨부)을 참고 하고 이 필 기 는 점차적으로 업 데 이 트 될 것 이다.본 고 는 자바 1.8.0 을 참고 하 였 다.45 버 전)
정의.
공식 문서 의 정의:
Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)
이것 은 List 인터페이스의 가 변 배열 의 실현 이다.선택 할 수 있 는 모든 list 작업 을 실 현 했 고 null 을 포함 한 모든 요 소 를 포함 할 수 있 습 니 다.List 인 터 페 이 스 를 실현 하 는 것 을 제외 하고 이 종 류 는 내부 에서 list 를 저장 하 는 배열 의 크기 를 조작 하 는 방법 을 제공 합 니 다.(이 큰 문 제 는 벡터 와 같 습 니 다.동기 화 되 지 않 는 것 을 제외 하고.)
Array List 는 가장 자주 사용 하 는 데이터 구조 중의 하나 이다.자바 집합 에 대한 설명(선택):
Array List 가 제한 을 초과 하면 50%용량 이 증가 하고 System.array copy()로 새 배열 로 복사 합 니 다.기본 값 으로 요 소 를 처음 삽입 할 때 10 크기 의 배열 을 만 듭 니 다.배열 아래 에 표 시 된 접근 요소-get(i),set(i,e)의 성능 이 매우 높다.아래 표 시 를 누 르 면 요소-add(i,e),reove(i),reove(e)를 삽입 하고 이동 부분 에 영향 을 받 는 요 소 를 System.array copy()로 복사 하면 성능 이 떨어진다.앞의 요소 일수 록 수정 할 때 이동 해 야 할 요소 가 많 습 니 다.배열 끝 에 요 소 를 직접 추가 합 니 다.자주 사용 하 는 add(e)는 마지막 요 소 를 삭제 하 는 데 영향 을 주지 않 습 니 다.
자동 용량 확장 에 대하 여
배열 의 용량 이 부족 할 때 원 배열 보다 용량 이 큰 새 배열 을 만 들 고 배열 의 요 소 를 새 배열 로 옮 긴 다음 에 새로운 요 소 를 새 배열 에 넣 고 마지막 으로 새 배열 을 원 배열 에 부여 하면 됩 니 다.
주 함수
구조 함수
코드 는 다음 과 같 습 니 다:
    /**
     * Constructs a new instance of {@code ArrayList} with the specified
     * initial capacity.
     *
     * @param capacity
     *            the initial capacity of this {@code ArrayList}.
     */
    public ArrayList(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("capacity < 0: " + capacity);
        }
        array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
    }

    /**
     * Constructs a new {@code ArrayList} instance with zero initial capacity.
     */
    public ArrayList() {
        array = EmptyArray.OBJECT;
    }

    /**
     * Constructs a new instance of {@code ArrayList} containing the elements of
     * the specified collection.
     *
     * @param collection
     *            the collection of elements to add.
     */
    public ArrayList(Collection extends E> collection) {
        if (collection == null) {
            throw new NullPointerException("collection == null");
        }

        Object[] a = collection.toArray();
        if (a.getClass() != Object[].class) {
            Object[] newArray = new Object[a.length];
            System.arraycopy(a, 0, newArray, 0, a.length);
            a = newArray;
        }
        array = a;
        size = a.length;
    }

위 코드 에서 보 듯 이 Array List 는 세 개의 구조 함수 가 있 습 니 다.첫 번 째 구조 함수 의 매개 변 수 는 용량 이 고 매개 변수 가 0 일 때 용량 이 0 인 Object 배열 을 형성한다.그렇지 않 으 면 용량 이 매개 변수 인 Object 배열 을 만 듭 니 다.두 번 째 는 우리 가 흔히 볼 수 있 는 것 이 니 군말 하지 않 는 것 이다.세 번 째 구조 함수 의 매개 변 수 는 collection 관련 클래스 입 니 다.먼저 부분 변수 a 를 현재 대상 toArray 의 값(현재 용기 에 있 는 모든 요 소 를 되 돌려 주 고 배열 형식 으로)이 라 고 설명 합 니 다.현재 부분 변수 a 의 유형 이 Object[]류 라면 직접 할당 작업 을 합 니 다.그렇지 않 으 면 System.array copy 작업 을 진행 합 니 다.System.array copy 작업 은 a 배열 의 요 소 를 모두 new Array(유형 은 Object[])에 복사 한 다음 에 똑 같이 할당 작업 을 합 니 다.
add 함수
코드 는 다음 과 같 습 니 다:
/**
     * Adds the specified object at the end of this {@code ArrayList}.
     *
     * @param object
     *            the object to add.
     * @return always true
     */
    @Override public boolean add(E object) {
        Object[] a = array;
        int s = size;
        if (s == a.length) {
            Object[] newArray = new Object[s +
                    (s < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        a[s] = object;
        size = s + 1;
        modCount++;
        return true;
    }

    /**
     * Inserts the specified object into this {@code ArrayList} at the specified
     * location. The object is inserted before any previous element at the
     * specified location. If the location is equal to the size of this
     * {@code ArrayList}, the object is added at the end.
     *
     * @param index
     *            the index at which to insert the object.
     * @param object
     *            the object to add.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location > size()}
     */
    @Override public void add(int index, E object) {
        Object[] a = array;
        int s = size;
        if (index > s || index < 0) {
            throwIndexOutOfBoundsException(index, s);
        }

        if (s < a.length) {
            System.arraycopy(a, index, a, index + 1, s - index);
        } else {
            // assert s == a.length;
            Object[] newArray = new Object[newCapacity(s)];
            System.arraycopy(a, 0, newArray, 0, index);
            System.arraycopy(a, index, newArray, index + 1, s - index);
            array = a = newArray;
        }
        a[index] = object;
        size = s + 1;
        modCount++;
    }

코드 에서 알 수 있 듯 이 Array List 류 는 두 개의 add 함 수 를 다시 불 러 왔 다.첫 번 째 add 함수 의 인 자 는 add 가 필요 한 요소 입 니 다.그것 의 역할 은 현재 이 요 소 를 배열 의 끝 에 추가 하 는 것 이다.함수 내 에서 size 는 ArrayList 의 요소 의 수량 이 고 a.length 는 현재 배열 의 길이 입 니 다.size 가 a.length 와 다 르 면 sizeObject[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ?MIN_CAPACITY_INCREMENT : s >> 1)];
새 배열 newArray 를 만 들 었 습 니 다.용량 은 이렇게 설정 되 어 있 습 니 다.현재 배열 의 길이 가 MIN 보다 작 으 면CAPACITY_INCREMENT(상수)의 절반 을 확대 하면 새로운 용량 을 원래 의 용량 에 MINCAPACITY_INCREMENT 의 값;그렇지 않 으 면 원래 용량 의 1.5 배로 확대 한다.
두 번 째 add 함 수 는 특정한 위치 에 요 소 를 삽입 하면 더 이상 군말 하지 않 습 니 다(코드 는 위 와 같 습 니 다).그러나 여기에 한 마디 를 추가 합 니 다.현재 요소 의 수량 이 배열 의 길이 보다 적 을 때 삽입 하 는 것 도 귀 찮 습 니 다.전체 배열 을 index 에서 뒤의 요 소 를 모두 뒤로 옮 겨 야 합 니 다.그래서 Array List 의 삽입 효율 이 높 지 않 을 것 입 니 다.
newCapacity 함수
앞에서 알 수 있 듯 이 new Capacity 함 수 는 확장 을 담당 하 는 것 으로 그 역할 은
Object[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ?MIN_CAPACITY_INCREMENT : s >> 1)];

비슷 합 니 다.그 코드 는 다음 과 같 습 니 다.
private static int newCapacity(int currentCapacity) {
        int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
                MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
        return currentCapacity + increment;
    }

이전 코드 가 왜 new Capacity 함 수 를 직접 인용 하지 않 았 는 지 모 르 겠 습 니 다~new Capacity 함수 해석 은 add 의 한 단락 과 같 아야 합 니 다.현재 배열 의 길이 가 MIN 보다 작 으 면CAPACITY_INCREMENT(상수)의 절반 을 확대 하면 새로운 용량 을 원래 의 용량 에 MINCAPACITY_INCREMENT 의 값;그렇지 않 으 면 원래 용량 의 1.5 배로 확대 한다.
addAll 함수
/**
     * Adds the objects in the specified collection to this {@code ArrayList}.
     *
     * @param collection
     *            the collection of objects.
     * @return {@code true} if this {@code ArrayList} is modified, {@code false}
     *         otherwise.
     */
    @Override public boolean addAll(Collection extends E> collection) {
        Object[] newPart = collection.toArray();
        int newPartSize = newPart.length;
        if (newPartSize == 0) {
            return false;
        }
        Object[] a = array;
        int s = size;
        int newSize = s + newPartSize; // If add overflows, arraycopy will fail
        if (newSize > a.length) {
            int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
            Object[] newArray = new Object[newCapacity];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        System.arraycopy(newPart, 0, a, s, newPartSize);
        size = newSize;
        modCount++;
        return true;
    }

    /**
     * Inserts the objects in the specified collection at the specified location
     * in this List. The objects are added in the order they are returned from
     * the collection's iterator.
     *
     * @param index
     *            the index at which to insert.
     * @param collection
     *            the collection of objects.
     * @return {@code true} if this {@code ArrayList} is modified, {@code false}
     *         otherwise.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location > size()}
     */
    @Override
    public boolean addAll(int index, Collection extends E> collection) {
        int s = size;
        if (index > s || index < 0) {
            throwIndexOutOfBoundsException(index, s);
        }
        Object[] newPart = collection.toArray();
        int newPartSize = newPart.length;
        if (newPartSize == 0) {
            return false;
        }
        Object[] a = array;
        int newSize = s + newPartSize; // If add overflows, arraycopy will fail
        if (newSize <= a.length) {
             System.arraycopy(a, index, a, index + newPartSize, s - index);
        } else {
            int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
            Object[] newArray = new Object[newCapacity];
            System.arraycopy(a, 0, newArray, 0, index);
            System.arraycopy(a, index, newArray, index + newPartSize, s-index);
            array = a = newArray;
        }
        System.arraycopy(newPart, 0, a, index, newPartSize);
        size = newSize;
        modCount++;
        return true;
    }

두 개의 addAll 함 수 를 다시 불 러 왔 습 니 다.첫 번 째 addAll 함 수 는 Collection 대상 의 요 소 를 배열 뒤에 삽입 합 니 다.기본 원 리 는 add 와 사실 매우 유사 하 다.두 번 째 addAll 함수 도 더 이상 군말 하지 않 습 니 다.
get 함수 와 set 함수
코드 는 다음 과 같 습 니 다:
@SuppressWarnings("unchecked") @Override public E get(int index) {
        if (index >= size) {
            throwIndexOutOfBoundsException(index, size);
        }
        return (E) array[index];
    }
/**
     * Replaces the element at the specified location in this {@code ArrayList}
     * with the specified object.
     *
     * @param index
     *            the index at which to put the specified object.
     * @param object
     *            the object to add.
     * @return the previous element at the index.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E set(int index, E object) {
        Object[] a = array;
        if (index >= size) {
            throwIndexOutOfBoundsException(index, size);
        }
        @SuppressWarnings("unchecked") E result = (E) a[index];
        a[index] = object;
        return result;
    }

get 함 수 는 매우 직접적 입 니 다.Array List 는 배열 이기 때문에 색인 을 통 해 직접 값 을 얻 으 면 됩 니 다.set 함수 역시 색인 을 통 해 해당 요소 의 내용 을 변경 합 니 다.그래서 Array List 의 액세스 효율 이 매우 빠 를 것 임 을 알 수 있다.
제거 함수
코드 는 다음 과 같 습 니 다:
/**
     * Removes the object at the specified location from this list.
     *
     * @param index
     *            the index of the object to remove.
     * @return the removed object.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E remove(int index) {
        Object[] a = array;
        int s = size;
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
        @SuppressWarnings("unchecked") E result = (E) a[index];
        System.arraycopy(a, index + 1, a, index, --s - index);
        a[s] = null;  // Prevent memory leak
        size = s;
        modCount++;
        return result;
    }

    @Override public boolean remove(Object object) {
        Object[] a = array;
        int s = size;
        if (object != null) {
            for (int i = 0; i < s; i++) {
                if (object.equals(a[i])) {
                    System.arraycopy(a, i + 1, a, i, --s - i);
                    a[s] = null;  // Prevent memory leak
                    size = s;
                    modCount++;
                    return true;
                }
            }
        } else {
            for (int i = 0; i < s; i++) {
                if (a[i] == null) {
                    System.arraycopy(a, i + 1, a, i, --s - i);
                    a[s] = null;  // Prevent memory leak
                    size = s;
                    modCount++;
                    return true;
                }
            }
        }
        return false;
    }

remove 함수 두 개 를 다시 불 러 왔 습 니 다.첫 번 째 remove 함수 의 인 자 는 색인 입 니 다.현재 색인 요 소 를 삭제 하 는 것 입 니 다.사실은 그 본질은 새로운 배열 을 복사 한 것 이다.작 동 하 는 배열 은 index+1 이 위치 에서 시작 하 는 오른쪽 모든 요 소 를 전체적으로 왼쪽으로 이동 하 는 동시에 a[s](즉,원래 배열 의 끝 요소)의 요 소 를 null 로 설정 하 는 것 이다.두 번 째 remove 함수 의 인 자 는 현재 삭제 해 야 할 요소 입 니 다.들 어 오 는 인자 가 null 이면 현재 배열 을 옮 겨 다 닙 니 다.한 요소 의 값 이 null 이면 이 요 소 를 제거 하고 복사 요소(System.array copy)방식 으로 현재 null 요소 의 위치 오른쪽 요 소 를 전체적으로 왼쪽으로 이동 합 니 다.들 어 오 는 인자 가 null 이 아 닐 때 도 현재 배열 을 옮 겨 다 니 며 하나의 요소 equals(인자)가 true 인 것 을 찾 으 면 위 와 같은 복사 작업 을 하여 삭 제 를 완료 합 니 다.위 에서 알 수 있 듯 이 삭제 작업 reove 역시 배열 의 복사 와 관련 되 기 때문에 Array List 의 reove 작업 의 효율 은 get,set 만큼 높 지 않 을 것 입 니 다.
작은 매듭
Array List 류 에는 위 에 열거 되 지 않 은 함수 도 있 습 니 다.나중에 제 가 보충 하 겠 습 니 다.(시간 이 있 으 면)Array List 는 거의 제 가 가장 자주 사용 하 는 용기 이기 때문에 저 는 특별히 필 기 를 한 편 써 서 자신의 이 해 를 적 었 고 다른 선배 들 의 글 도 참고 하 였 습 니 다.(그들의 자바 버 전 은 저 와 다 르 고 구체 적 인 함수 실현 은 약간 차이 가 있 을 수 있 습 니 다)자신의 언어 이기 때문에 잘 모 르 는 부분 이 있 을 수 있 습 니 다.어디 에 잘못 썼 는 지 지적 해 주세요.감사합니다.
참고:자바 집합 에 관 한 커닝 자바 ArrayList 작업 원리 및 ArrayList 원리 실현 및 학습 총화

좋은 웹페이지 즐겨찾기