Позвольте мне помочь вам здесь ...
Хешированные коллекции являются наиболее эффективными для добавления, поиска и удаления данных, поскольку они хэшируют ключ (в HashMap) или элемент (в HashSet) для поиска.место, где они принадлежат в один шаг.Концепция хеширования действительно проста.Это процесс представления объекта в виде числа, которое может работать как его идентификатор.Например, если у вас есть строка в Java, такая как String name = "Jeremy";
, и вы напечатали ее хэш-код: System.out.println(name.hashCode());
, вы увидите там большое число (-2079637766), которое было создано с использованием значений этого строкового объекта (в этом строковом объекте)., это символы), таким образом, это число можно использовать в качестве идентификатора для этого объекта.
Таким образом, коллекции Hashed, подобные упомянутым выше, используют это число, чтобы использовать его в качестве индекса массива для поиска элементов.мгновенно.Но, очевидно, он слишком велик, чтобы использовать его в качестве индекса массива для возможного небольшого массива.Поэтому им нужно уменьшить это число, чтобы оно соответствовало диапазону размеров массива.(HashMap и HashSet используют массивы для хранения своих элементов).
Операция, которую они используют для уменьшения этого числа, называется хешированием и выглядит примерно так: Math.abs(-2079637766 % arrayLength);
.Это не совсем так, это немного сложнее, но это для упрощения.Допустим, что arrayLength = 16;Оператор% уменьшит это большое число до числа, меньшего 16, чтобы его можно было уместить в массиве.
Именно поэтому коллекция Hashed не будет разрешать дублирование, поскольку при попытке добавить то же самоеобъект или эквивалентный (например, 2 строки с одинаковыми символами), он создаст один и тот же хэш-код и переопределит любое значение в индексе результата.
В своем вопросе вы упомянули, что если вас беспокоитдублирует элементы в ArrayList, мы можем просто проверить, есть ли элемент перед его вставкой, поэтому таким образом нам не нужно использовать HashSet.Но это не очень хорошая идея, потому что если вы вызываете метод list.contains(elem);
в ArrayList, он должен идти один за другим, сравнивая элементы, чтобы увидеть, есть ли он там.Если у вас есть 1 миллион элементов в ArrayList, и вы проверяете, есть ли элемент, но его там нет, ArrayList итерировал более 1 миллиона элементов, что не очень хорошо.Но с HashSet, он будет только хэшировать объект и идти прямо туда, где он должен быть в массиве, и проверять, делая это всего за 1 шаг вместо 1 миллиона.Итак, вы видите, насколько эффективен HashSet по сравнению с ArrayList.
То же самое происходит с HashMap размером 1 миллион, что для проверки наличия ключа требуется всего один шаг, а не 1 миллион,То же самое происходит, когда вам нужно добавить, найти и удалить элемент, с хэшированными коллекциями он сделает все это за один шаг (постоянное время, не зависит от размера карты), но это зависит от другихструктуры.
Вот почему он действительно эффективен и широко используется.
Основное различие между ArrayList и LinkedList:
Если вы хотите найтиэлемент в месте 500 в ArrayList размера 1000, вы делаете: list.get(500);
, и он сделает это за один шаг, потому что ArrayList реализован с массивом, поэтому с этим 500 он идет прямо туда, где находится элементмассив.Но LinkedList реализован не с массивом, а с объектами, указывающими друг на друга.Таким образом, они должны идти линейно и считать от 0, один за другим, пока не доберутся до 500, что не очень эффективно по сравнению с 1 единственным шагом ArrayList.Но когда вам нужно добавить и удалить элементы в ArrayList, иногда необходимо воссоздать массив, чтобы в него поместилось больше элементов, что увеличило накладные расходы.Но этого не происходит с LinkedList, так как никакой массив не должен быть воссоздан, только ссылки на объекты (узлы) должны быть сделаны повторно, что делается за один шаг.
Так что ArrayList хорошкогда вы не будете удалять или добавлять много элементов в структуру, но вы будете много читать из нее.яЕсли вы собираетесь добавить и удалить много элементов, то лучше связать список, так как он выполняет меньше операций с этими операциями.
Почему вам нужно реализовать методы equals (), hashCode () для пользовательских классов, когда вы хотите использовать эти объекты в HashMaps, и реализовать интерфейс Comparable, когда вы хотите использовать эти объекты с TreeMaps?
Исходя из того, что я упоминал ранее для HashMaps, возможно, что 2 разных объекта выдают один и тот же хеш, если это произойдет, Java не переопределит предыдущий или не удалит его, но сохранит их обоих в одном индексе. Вот почему вам нужно реализовать hashCode (), поэтому вы должны убедиться, что ваши объекты не будут иметь действительно простого hashCode, который можно легко скопировать.
И причина, по которой рекомендуется переопределить метод equals (), заключается в том, что если коллизия (2 или более объектов совместно используют один и тот же хэш в HashMap) , то как вы их отличите? Хорошо, спрашивая метод equals () этих двух объектов, если они одинаковы. Поэтому, если вы спрашиваете карту, содержит ли она определенный ключ, и в этом индексе он находит 3 элемента, он запрашивает методы equals () этих элементов, если его equals () переданному ключу, если да, возвращает вон тот. Если вы не переопределите метод equals () и не укажете, что именно вы хотите проверить на равенство (например, имя свойства, возраст и т. Д.), Тогда произойдут некоторые нежелательные переопределения внутри HashMap, и вам это не понравится.
Если вы создаете свои собственные классы, скажем, Person, и имеете такие свойства, как name, age, lastName и email, вы можете использовать эти свойства в методе equals (), и если 2 разных объекта передаются, но имеют одинаковые значения в Вы выбрали свойства для равенства, затем вы возвращаете true, чтобы указать, что они одинаковы, или false в противном случае. Как и класс String, если вы делаете s1.equals(s2);
, если s1 = new String("John");
и s2 = new String("John");
, даже если они являются разными объектами в памяти кучи Java, реализация метода String.equals использует символы, чтобы определить, равны ли объекты, и он возвращает true для этого примера.
Чтобы использовать TreeMap с пользовательскими классами, вам необходимо реализовать Comparable интерфейс , так как TreeMap будет сравнивать и сортировать объекты на основе некоторых свойств, вам необходимо укажите, по каким свойствам будут отсортированы ваши объекты. Будут ли ваши объекты отсортированы по возрасту? По имени? По идентификатору? Или любой другой собственностью, которую вы хотели бы. Затем, когда вы реализуете интерфейс Comparable и переопределяете метод compareTo (UserDefinedClass o) , вы выполняете логику и возвращаете положительное число, если текущий объект больше, чем переданный объект o, 0, если они являются то же самое и отрицательное число, если текущий объект меньше. Таким образом, TreeMap будет знать, как их сортировать, основываясь на возвращенном числе.