Почему в ArrayList есть метод get() и как он реализован?

Ответ

Метод get() присутствует в ArrayList благодаря реализации интерфейса List<E>, который объявляет этот метод как обязательный для доступа к элементам по индексу.

Иерархия интерфейсов:

Iterable<E> (итерация)
    ↓
Collection<E> (базовые операции коллекции)
    ↓
List<E> (упорядоченная коллекция с доступом по индексу)
    ↓
ArrayList<E> (реализация на основе массива)

Реализация в ArrayList:

public E get(int index) {
    // Проверка выхода за границы (с Java 9)
    Objects.checkIndex(index, size);
    // Прямой доступ к элементу массива - O(1)
    return elementData[index];
}

Ключевые особенности:

  1. Сложность O(1) - доступ к элементу происходит за константное время, так как используется обычный массив
  2. Проверка границ - метод проверяет, что индекс находится в диапазоне [0, size-1]
  3. Type safety - благодаря дженерикам, возвращаемый тип соответствует типу коллекции

Пример использования:

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
String element = list.get(1); // "B" - получение за O(1)

// Сравнение с LinkedList (реализация get() через итерацию)
List<String> linkedList = new LinkedList<>(list);
String linkedElement = linkedList.get(1); // O(n) - требует обхода

Важно: Метод get() выбрасывает IndexOutOfBoundsException, если индекс выходит за пределы списка.

Ответ 18+ 🔞

А, слушай, вот эта вся история с get() в ArrayList — это вообще отдельный цирк с конями, если разобраться. Ну типа, смотри, блядь: вроде бы обычный метод, доступ по индексу, чего уж проще. Но нет, ёпта, тут под капотом целая опера разворачивается!

Так вот, этот самый get() у ArrayList появляется не потому, что он такой умный сам по себе, а потому что он, сука, обязан его реализовать! А обязан он потому, что подписал контракт — интерфейс List<E>. Это как если бы ты пошёл в армию, блядь: там тебе говорят «надо», и ты, хочешь не хочешь, делаешь. Вот и ArrayList — он делает.

Вся эта иерархия выглядит примерно так, представь:

Iterable<E> (может просто по себе пройтись, как бомж по помойке)
    ↓
Collection<E> (уже может кучу базового дерьма делать — добавить, удалить)
    ↓
List<E> (а вот тут уже конкретика: «дай мне элемент по номеру, сука!»)
    ↓
ArrayList<E> (и вот он, наш герой, который это всё реализует на массиве)

А внутри ArrayList этот метод get() — это просто праздник какой-то, блядь:

public E get(int index) {
    // Сначала, как порядочный гражданин, проверяет, не вышел ли ты за рамки дозволенного
    Objects.checkIndex(index, size);
    // А потом — бац! — и достаёт из своего внутреннего массива элемент за O(1)
    return elementData[index];
}

И вот в чём, блядь, соль, понимаешь:

  1. Скорость — огонь! O(1), потому что под капотом обычный массив. Тыкнул пальцем — получил. Никаких тебе обходов, никаких итераций, чистая математика, адресная арифметика, ёба!
  2. Проверяет границы. Не даст тебе, распиздяю, ткнуть в -1 или в размер+1. Скажет тебе «нет, дружок, иди нахуй» через IndexOutOfBoundsException.
  3. Типизация. Благодаря дженерикам, он тебе вернёт именно String, а не какую-нибудь хуйню в виде Object, которую потом надо кастовать.

Ну и чтобы совсем понятно было, смотри пример:

// Создаём наш быстрый ArrayList
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
String element = list.get(1); // Вытащил "B" моментально, как фокусник из рукава!

// А вот для сравнения — LinkedList, блядь
List<String> linkedList = new LinkedList<>(list);
String linkedElement = linkedList.get(1); // А вот тут уже O(n) — он будет ползти от начала списка, как черепаха, ебать её в сраку!

И главное, запомни, как отче наш: если попробуешь вызвать get(999) на списке из трёх элементов, получишь не элемент, а пиздюлину в виде исключения. Так что с индексами, дружище, аккуратнее, а то мало не покажется!