2021-Руководство по собеседованию с бэкенд-инженером Java-(Основы Java)

опрос

предисловие

Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/bin39232820…
Лучшее время посадить дерево было десять лет назад, затем сейчас

Tips

Серия руководств по собеседованию во многих случаях не будет вдаваться в подробности. Это способ для Сяолиу Лю проверить знания в роли интервьюируемого, поэтому я не выполняю большинство вещей. Как интервьюер, вы должны понимать.

woohoo.process on.com/view/lincoln/6…

Выше указан адрес карты мозга.

слухи

Всем это может показаться немного банальным, и это так. Вопросы-интервью, сборники интервью, просто ищите, все не прочитаешь, да и не прочитаешь, так какой смысл это писать? Собственно, я написал это для следующей цели

  • Во-первых, просмотреть статьи, написанные перед вами, путем систематического обзора, а также обобщить и сублимировать.
  • Во-вторых, помочь всем установить систему обзора, написав статьи.Я дам вам представление о большинстве пунктов знаний, которые будут заданы в форме точки и лица.

Затем следует краткое изложение предыдущих статей.

Наконец, я рассмотрю все точки знаний в форме вопросов для интервью и разберу некоторые из наиболее распространенных вопросов для интервью и проблемы, с которыми я столкнулся в процессе моего фактического развития.

Основы Java

В чем разница между символьными константами Java и строковыми константами?

В процессе разработки мы должны больше использовать строки, поэтому, чтобы быть знакомыми с символьными константами, мы можем ответить

  • Формально: символьные константы — это один символ, заключенный в одинарные кавычки; строковые константы — ноль или более символов, заключенные в двойные кавычки.
  • Значение: символьная константа эквивалентна целочисленному значению (значение ASCII), которое может участвовать в операциях выражения; строковая константа представляет адресное значение (где строка хранится в памяти)
  • Занимают размер памяти Символьные константы занимают всего 2 байта, строковые константы занимают несколько байтов.

Разница между String и StringBuilder, StringBuffer?

  • Платформа Java предоставляет два типа строк: String и StringBuffer/StringBuilder, которые могут хранить строки и управлять ими.
  • Среди них String является строкой только для чтения, что означает, что содержимое строки, на которую ссылается String, не может быть изменено.
  • Строковый объект, представленный классом StringBuffer/StringBuilder, можно изменять напрямую. StringBuilder был представлен в Java 5. У него точно такой же метод, как у StringBuffer, разница в том, что он используется в однопоточной среде, потому что все его аспекты не изменяются синхронизацией, поэтому его эффективность также выше, чем у StringBuffer.

Сяо Люлю говорит об этом, а на самом деле увещевает себя.На самом деле, я полагаю, что большинство людей знают ответ на этот вопрос, и они знакомы с ним, но мы действительно не соблюдали его в процессе разработки. Например, когда мы имеем дело с какой-то логикой, мы привыкли использовать +, когда нам нужно соединить некоторые поля. Ха-ха, Сяо Люлю и все вместе пытаются выработать хорошие привычки развития.

Расскажите об использовании и реализации отражения

Механизм отражения Java — очень мощная функция, и отражение можно увидеть во многих проектах, таких как Spring и MyBatis. С помощью механизма отражения мы можем получить информацию о типе объекта во время выполнения. Используя это, мы можем реализовывать шаблоны проектирования, такие как Factory и Proxy, а также решать неприятные проблемы, такие как стирание дженериков Java.

Получить класс отражения, соответствующий объекту.В Java есть следующие методы для получения класса отражения объекта.

  • новый объект, затем метод object.getClass()
  • Через метод Class.forName()
  • использовать class.class

Расскажите о том, сталкивались ли вы с ямой BigDecimal, или на что обратить внимание

  • Когда мы используем BigDecimal, для предотвращения потери точности рекомендуется использовать его конструктор BigDecimal(String) для создания объектов.

На самом деле, я просто хочу знать, заметила ли наша актуальная разработка эти моменты,

Расскажите, как вы обычно превращаете строку, разделенную запятыми, в множество, подобное ("1,2,3")

  • List myList = Arrays.stream(myArray).collect(Collectors.toList()), рекомендуется использовать этот метод вместо List myList = Arrays.asList(1, 2, 3);
  • Что касается причины, после того, как Arrays.asList() преобразует массив в коллекцию, нижний слой на самом деле является массивом.

Расскажите о разнице между String s="abc" и String s=new String("abc");

  • Я считаю, что всем не чужд этот вопрос, и ответ хорошо известен, 1 или 2.
  • Сначала создайте указанный объект «abc» в куче (не в постоянном пуле) и позвольте ссылке str указывать на этот объект
  • Проверьте пул строковых констант, чтобы увидеть, есть ли строковый объект с содержимым «abc».
  • Если он существует, свяжите новый строковый объект с объектом в пуле строковых констант.
  • Если нет, создайте строковый объект «ABC» в пуле строковых констант и свяжите объекты в стеке.

Разговор о SPI в Java

Часто существует множество различных схем реализации для каждой абстракции проектирования системы.В объектно-ориентированном проектировании обычно рекомендуется программирование интерфейсов между модулями, а классы реализации не жестко закодированы между модулями. Как только в код вовлекается конкретный класс реализации, нарушается принцип подключаемости: если нужно заменить реализацию, нужно модифицировать код. Для того, чтобы понять, что его нельзя динамически указать в программе при сборке модуля, нужен механизм обнаружения сервисов. Java SPI предоставляет такой механизм: механизм поиска реализации службы для интерфейса. Это чем-то похоже на идею IOC, которая заключается в том, чтобы вынести управление сборкой за пределы программы.Этот механизм особенно важен в модульном дизайне. Итак, основная идея SPI — развязка.

Расскажите об особенностях Java 8.

  • функциональный интерфейс
  • Интерфейсы могут иметь методы реализации, а реализующие классы не обязаны реализовывать свои методы.
  • лямбда-выражение
  • поток поток
  • Date Time API LocalDateTime год месяц день десять секунд; дата LocalDate; время LocalTime
  • Необязательный класс

Хотя последняя версия уже 15, большинство компаний до сих пор используют 8, так что давайте поговорим об этой тяге.

В чем разница между переменными-членами и локальными переменными?

  • Переменные-члены могут быть изменены с помощью таких модификаторов, как public, private, static и т. д., в то время как локальные переменные не могут быть изменены с помощью модификаторов управления доступом и static; однако как переменные-члены, так и локальные переменные могут быть изменены с помощью final.
  • С точки зрения метода хранения переменных в памяти: если переменная-член модифицируется статической, то переменная-член принадлежит классу, а если она не модифицируется статической, переменная-член принадлежит экземпляру. В то время как объекты существуют в куче памяти, локальные переменные существуют в памяти стека.
  • С точки зрения времени выживания переменных в памяти: переменные-члены являются частью объекта, которые существуют при создании объекта, а локальные переменные автоматически исчезают при вызове метода.
  • Если переменной-члену не присвоено начальное значение: ей будет автоматически присвоено значение типа по умолчанию (исключение: переменные-члены, измененные с помощью final, также должны быть явно назначены), в то время как локальные переменные не будут автоматически назначены.

Каковы особенности метода строительства?

  • Имя совпадает с именем класса.
  • Возвращаемого значения нет, но конструктор не может быть объявлен с пустым значением.
  • Автоматически выполняется при создании объекта класса, вызывать не нужно.

Разговор о == и равных

  • == : его функция состоит в том, чтобы определить, равны ли адреса двух объектов. То есть, чтобы определить, являются ли два объекта одним и тем же объектом (базовый тип данных == сравнивает значение, ссылочный тип данных == сравнивает адрес памяти).
  • equals() : его функция также состоит в том, чтобы определить, равны ли два объекта. Но обычно у него есть два варианта использования:
    • Случай 1: класс не переопределяет метод equals(). Тогда сравнение двух объектов этого класса через equals() эквивалентно сравнению двух объектов через "==".
    • Случай 2: класс переопределяет метод equals(). Обычно мы переопределяем метод equals(), чтобы сравнить содержимое двух объектов на равенство; если их содержимое равно, вернуть true (т. е. считать два объекта равными).

Давайте поговорим о четырех отсылках к Java, сильных и слабых.

Сяо Люлю сказал здесь, на самом деле, будучи грубым мальчиком, то, с чем мы действительно сталкиваемся в обычное время, может быть сильным цитированием, но это не означает, что другие методы цитирования бесполезны, и они разумны, если они существуют. посмотрите на их конкретные роли. ! Такое ощущение, что его надо поместить в модуль JVM, забудьте, вот он

  • Сильная ссылка: наиболее распространенный метод ссылки, такой как String s = "abc", переменная s является строгой ссылкой на строку "abc". Пока существует сильная ссылка, сборщик мусора не будет перерабатывать объект.
  • Мягкая ссылка: используется для описания объектов, которые все еще полезны, но не являются необходимыми.Если памяти достаточно, она не будет восстановлена, а если памяти недостаточно, она будет восстановлена. Обычно используемые для реализации кэшей, чувствительных к памяти (используемых при кэшировании пользовательской памяти), мягкие ссылки могут использоваться в сочетании с очередью ссылок ReferenceQueue, если объект, на который ссылаются, является сборщиком мусора, JVM добавит к нему мягкую ссылку. очередь.
  • Слабые ссылки: Слабые ссылки и мягкие ссылки примерно одинаковы.Разница между слабыми ссылками и мягкими ссылками заключается в том, что объекты только со слабыми ссылками имеют более короткий жизненный цикл. В процессе сканирования области памяти, находящейся под юрисдикцией потока сборщика мусора, как только будет найден объект только со слабыми ссылками, его память будет освобождена независимо от того, достаточно ли текущего места в памяти или нет. (это скорее бред)
  • Фантомные ссылки: Фантомные ссылки не меняют время жизни объекта, если объект содержит только фантомную ссылку, то это то же самое, как если бы он вообще не имел ссылки. (На самом деле собственное понимание виртуальных ссылок Сяо Люлю все еще связано с ThreadLocal, что не дает нам забыть удалить)

Коллекция контейнеров Java

Поговорим о характеристиках массивов

  • Непротиворечивость: массивы могут содержать элементы только одного типа данных, а типы данных элементов могут быть любыми из одних и тех же типов данных.
  • Упорядочено: элементы в массиве упорядочены и доступны по нижнему индексу.
  • Неизменяемость: после инициализации массива его длина (количество элементов в массиве) неизменна. Массив представляет собой непрерывную линейную структуру хранения с элементами одного типа и одинакового размера.

Каковы общие коллекции в Java

Думаю, этот вопрос будет часто задаваться, это введение в коллекционный тест.

  • Интерфейс карты и интерфейс коллекции являются родительскими интерфейсами всех фреймворков коллекций.
  • Подинтерфейсы интерфейса коллекции включают в себя: интерфейс установки и интерфейс списка.
  • Классы реализации интерфейса карты в основном включают: HashMap, TreeMap, Hashtable, ConcurrentHashMap и свойства и т. д.
  • Классы реализации интерфейса Set в основном включают: HashSet, TreeSet, LinkedHashSet и т. д.
  • Классы реализации интерфейса List в основном включают в себя: ArrayList, LinkedList, Stack и Vector и т. д.

Кратко поговорим о разнице между Set, List и Map

List

  • Дублирование объектов разрешено.
  • Можно вставить несколько нулевых элементов.
  • Это упорядоченный контейнер, который поддерживает порядок вставки каждого элемента, а порядок вывода — это порядок вставки.

Set

  • Повторяющиеся объекты не допускаются
  • Неупорядоченные контейнеры, вы не можете гарантировать порядок хранения каждого элемента, TreeSet поддерживает порядок сортировки через Comparator или Comparable.
  • Допускается только один нулевой элемент

Map

  • Карта не является субинтерфейсом или реализующим классом коллекции. Карта — это интерфейс.
  • Каждая запись карты содержит два объекта, то есть ключ и значение Карта может содержать один и тот же объект значения, но ключевой объект должен быть уникальным.
  • У вас может быть столько нулевых значений, сколько вы хотите на карте, но может быть только один нулевой ключ.

варианты их использования

  • Если вы часто используете индекс для доступа к элементам в контейнере, то List — правильный выбор для вас. Если вы уже знаете индекс, то классы реализации List, такие как ArrayList, могут обеспечить более быстрый доступ.Если вы часто добавляете и удаляете элементы, то однозначно выбирайте LinkedList.
  • Если вы хотите, чтобы элементы в контейнере сохранялись в том порядке, в котором они были вставлены, то это все еще список, потому что список — это упорядоченный контейнер и он хранится в порядке вставки.
  • Если вы хотите обеспечить уникальность вставляемых элементов, то есть не хотите иметь повторяющиеся значения, то вы можете выбрать класс реализации Set, такой как HashSet, LinkedHashSet или TreeSet. Все классы реализации Set следуют унифицированным ограничениям, таким как уникальность, а также предоставляют дополнительные функции, такие как TreeSet или SortedSet. Все элементы, хранящиеся в TreeSet, можно сортировать с помощью Comparator или Comparable в Java. LinkedHashSet также сохраняет элементы в том порядке, в котором они были вставлены.
  • Если вы храните данные в виде ключей и значений, то Map — правильный выбор для вас. Вы можете выбрать Hashtable, HashMap, TreeMap в соответствии с вашими последующими потребностями. `

Давайте поговорим о разнице между ArrayList и LinkedList.

  • ArrayList — это структура данных, основанная на динамических массивах, а LinkedList — структура данных, основанная на связанных списках.
  • Для получения и установки произвольного доступа ArrayList лучше, чем LinkedList, потому что LinkedList должен перемещать указатель.
  • Для операций добавления и удаления добавление и удаление LinedList является более доминирующим, поскольку ArrayList должен перемещать данные.

Расскажите о разнице между Vector и ArrayList:

  • Все методы Vector синхронизированы и потокобезопасны, а методы ArrayList — нет.Поскольку синхронизация потоков неизбежно влияет на производительность, производительность ArrayList лучше, чем у Vector.
  • Когда элементы в Vector или ArrayList превышают свой первоначальный размер, Vector удвоит свою емкость, а ArrayList увеличит свой размер только на 50% Таким образом, ArrayList поможет сэкономить место в памяти.
  • Мы также можем использовать Collections.synchronizedList для создания потокобезопасного списка.

Расскажите о разнице между HashSet и TreeSet:

  • TreeSet реализуется бинарным деревом, данные в Treeset автоматически сортируются, нулевые значения не допускаются.
  • HashSet реализуется хэш-таблицей.Данные в HashSet неупорядочены и могут быть помещены в null, но может быть введен только один null.Значения в обоих не могут повторяться, как и уникальное ограничение в базе данных.
  • HashSet требует, чтобы размещаемые объекты реализовывали метод HashCode().Размещаемые объекты идентифицируются по хэш-коду, а объекты String с одинаковым содержимым имеют одинаковый хэш-код, поэтому размещаемое содержимое не может быть повторено. Но объекты одного класса могут быть помещены в разные экземпляры.

Расскажите о разнице между HashMap и HashTable:

  • HashMap не является потокобезопасным, Hashtable — потокобезопасным, поэтому Hashtable тяжелее, поскольку для обеспечения безопасности потоков используется ключевое слово synchronized.
  • HashMap позволяет и ключу, и значению быть нулевыми, в то время как Hashtable не может быть нулевым.
  • Итератор HashMap (Iterator) — отказоустойчивый итератор, а итератор перечислителя Hashtable — не отказоустойчивый. Таким образом, когда другие потоки изменяют структуру HashMap (добавляют или удаляют элементы), будет выброшено ConcurrentModificationException, но метод remove() самого итератора не выдаст ConcurrentModificationException.

Вышеизложенное является основой нашей коллекции, давайте взглянем на некоторые дополнительные вопросы для интервью.

Можете ли вы подробно описать ArrayList?

  • Размер массива без параметров по умолчанию равен 10.
  • Обход ArrayList с помощью цикла for выполняется быстрее, чем обход итератора с помощью итератора.
  • Давайте подытожим его процесс расширения вместе.Первый шаг - определить, требуется ли расширение (то есть путем вычисления текущей длины моего массива плюс длина, которую я хочу добавить к массиву, и minCapacity для сравнения с текущей емкостью, если это необходимо , то Для первого расширения емкость первого расширения в 1,5 раза больше исходного размера.После расширения сравните значение после расширения с предыдущим значением minCapacity.Если оно все еще мало, выполните второе расширение для расширения емкости.Если minCapacity больше максимальной емкости, емкость будет увеличена до максимальной емкости около 2,1 миллиарда.

Почему elementData ArrayList украшен переходным

  • ArrayList реализует интерфейс Serializable, что означает, что ArrayList может быть сериализован, а изменение elementData с помощью переходного процесса означает, что я не хочу сериализовать массив elementData.
  • При сериализации ArrayList elementData в ArrayList может быть не полным.Например, elementData имеет размер 10, но я использую только 3 из них, поэтому необходимо ли сериализовать все elementData? Очевидно, что в этом нет необходимости, поэтому метод writeObject переопределяется в ArrayList.

Вы переписали hashcode и equals, почему вам нужно переписать метод hashCode при переписывании equals?

  • Если два объекта равны, хэш-код также должен быть одинаковым.
  • Если два объекта равны, вызов метода equals для обоих объектов возвращает значение true.
  • Два объекта имеют одинаковое значение хэш-кода, они не обязательно равны
  • Следовательно, если метод equals переопределен, метод hashCode также должен быть переопределен.
  • Поведение hashCode() по умолчанию заключается в создании уникальных значений для объектов в куче. Без переопределения hashCode() два объекта этого класса в любом случае не будут равны (даже если два объекта указывают на одни и те же данные)

Расскажите о том, как HashSet проверяет наличие дубликатов.

Когда вы добавляете объект в HashSet, HashSet сначала вычисляет значение хэш-кода объекта, чтобы определить, куда добавляется объект, а также сравнивает его со значениями хэш-кода других добавленных объектов.Если нет соответствующего хэш-кода, HashSet будет предполагать, что объект не появляется повторно. Но если будут найдены объекты с одинаковым значением хэш-кода, будет вызван метод equals(), чтобы проверить, действительно ли объекты с одинаковыми хэш-кодами одинаковы. Если они совпадают, HashSet не позволит успешно выполнить операцию соединения.

Расскажите о базовой реализации HashMap.

До JDK1.8

До JDK1.8 нижний уровень HashMap представлял собой комбинацию массива и связанного списка, то есть хэширование связанного списка. HashMap получает хэш-значение, обрабатывая хэш-код ключа с помощью функции возмущения, а затем оценивает место, где хранится текущий элемент, с помощью (n - 1) и хэша (где n относится к длине массива). является элементом в текущей позиции, оцените, совпадают ли хэш-значение и ключ элемента и сохраняемого элемента, если они совпадают, перезапишите их напрямую.Если они разные, разрешите конфликт с помощью метода zipper .

Так называемая функция возмущения относится к хеш-методу HashMap. Использование хеш-метода, то есть функции возмущения, предназначено для предотвращения некоторых плохо реализованных методов hashCode(), Другими словами, коллизия может быть уменьшена после использования функции возмущения.

После JDK1.8

По сравнению с предыдущей версией, после JDK1.8 произошли серьезные изменения в разрешении конфликтов хэшей.Когда длина связанного списка превышает пороговое значение (по умолчанию 8) (это будет оцениваться перед преобразованием связанного списка в красно-черное дерево, если текущий массив Если длина меньше 64, то вместо преобразования в красно-черное дерево массив будет расширен, а связанный список будет преобразован в красно-черное дерево для уменьшения время поиска.

Так можно ли говорить о красно-черных деревьях?

Прежде всего, мы знаем, что красно-черное число является бинарным деревом поиска, которое имеет следующие характеристики

  • Значение всех узлов в левом поддереве меньше или равно значению его корневого узла.
  • Значение всех узлов в правом поддереве больше или равно значению его корневого узла.
  • Левое и правое поддеревья также являются деревьями с бинарной сортировкой соответственно.

Однако в крайних случаях общее бинарное дерево может стать линейным поиском, и тогда оно потеряет свои поисковые характеристики.Красно-черное дерево является самобалансирующимся деревом.Самое главное, добавить следующие три правила для обеспечения это самобалансирующийся

  • Каждый листовой узел является черным пустым узлом (узел NIL).
  • Оба потомка каждого красного узла черные. (Не может быть двух последовательных красных узлов на всех путях от каждого листа к корню)
  • Все пути от любого узла к каждому его листу содержат одинаковое количество черных узлов.

Тут Сяо Люлю сказал, что красно-черное дерево все-таки очень сложное, так что вообще не буду о нем спрашивать, если немного ненормально, то спрошу про процесс самобалансировки, объяснять не буду на один здесь., чтобы найти. Это обесцвечивание, это левша, правша, лол, он теряет волосы. .

Почему длина HashMap равна степени 2?

  • Прежде всего, учтите, что нечетная строка не годится, при вычислении хеша, при определении позиции массива метод вычисления (n - 1) & hash, нечетное n-1 - это четное число, а конец четной двоичной системы равен 0. После того, как конец операции & равен 0, это увеличит конфликт хэшей, и в половине пространства не будет данных
  • Почему это степень двойки, разве она не может быть кратна 2, например 6, 10?
    • Структура hashmap представляет собой массив, а структура в каждом массиве представляет собой узел (связный список или красно-черное дерево).В обычных условиях, если вы хотите поместить данные в другое место, вы обязательно подумаете о том, чтобы взять остаток для определения этих данных.Формула расчета: hash % n, это десятичное вычисление. В компьютере (n - 1) & hash, когда n является степенью числа 2, будет удовлетворять формуле: (n - 1) & hash = hash % n, вычисление будет более эффективным.
    • Только после того, как число, являющееся степенью двойки, пройдет через n-1, двоичный файл должен быть в формате... 11111111. При вычислении позиции (&) в этом формате она полностью определяется сгенерированным классом хэш-значения , а не на n-1 (двоичное число длины группы). Вы можете подумать, Не лучше ли быть затронутым? Я вычислил это снова. Подобно функции возмущения, хеш-конфликт может быть ниже. Здесь нам нужно рассмотреть расширение. Степень 2 * 2, таких как 4 и 8 в двоичном виде, представляет значение 2. 2-я степень и 3-я степень, их бинарная структура аналогична, например 4 и 8 00000100 0000 1000 просто переместите старший бит вперед на один бит, поэтому при расширении емкости вам нужно только оценить хэш старшего бита и переместить его на кратное предыдущей позиции, избавляя от необходимости пересчитывать позицию.

Почему значение расширения HashMap равно 0,75?

  • Когда коэффициент загрузки равен 1,0, это означает, что расширение произойдет только тогда, когда будут заполнены все 8 значений массива (эта цифра представляет 8). Это приводит к большой проблеме, потому что конфликтов хэшей не избежать. Когда коэффициент нагрузки равен 1,0, это означает, что будет много конфликтов хэшей, и базовое красно-черное дерево станет чрезвычайно сложным. Это крайне неблагоприятно для эффективности запросов. В этом случае время приносится в жертву для обеспечения использования пространства.
  • Когда коэффициент загрузки равен 0,5, это означает, что расширение начинается, когда элементы в массиве достигают половины.Поскольку элементов заполнено меньше, конфликт хэшей также будет уменьшен, поэтому длина базового связанного списка или высота красно-черное дерево уменьшится. Эффективность запросов повысится.
  • По сути, ответ на вопрос, почему он равен 0,75, выходит: это компромисс между временем и пространством.

Условия дерева HashMap

Этот маленький Люлю сказал, что если вы не читали исходный код, вы должны быть менее впечатлены.

  • Первый должен быть хеш-коллизией
  • И если длина связанного списка больше 8, то он будет древовидным, а если меньше 6, то вырожденным.
  • Другим условием является то, что емкость всей хеш-карты должна быть больше 64.

Знаете ли вы проблему бесконечного цикла hashmap версии JDK1.7?

Xiaoliuliu также примерно сказал, что в случае многопоточности 1.7, при расширении, предполагая, что два потока одновременно расширяют емкость нашего связанного списка, взаимная ссылка нашего связанного списка приведет к бесконечному циклу, который мы называем связанным вставка хвоста списка На самом деле это не ошибка, потому что официальный сказал, что hashmap не должен использоваться в многопоточной среде.

Разговор об операции put хэшмапа

  • Первым шагом, конечно же, является вычисление хеш-значения ключа (который был обработан (h = key.hashCode()) ^ (h >>> 16))
  • Второй шаг — вызвать метод putval, а затем определить, пуст ли весь контейнер, и если да, то расширить вместимость контейнера.
  • Третий шаг — вычислить & значение максимальной емкости и значение хеша (i = (n — 1) & hash), определить, есть ли в индексе этого массива данные, и если нет, то подставить их. Также оцените метод equals ключа, чтобы увидеть, нужно ли его переопределять.
  • Четвертый шаг, если есть, значит, произошла коллизия, затем продолжаем обход, чтобы определить, больше ли длина связанного списка 8, и если она больше 8, продолжаем превращать текущий связанный список в красно-черная древовидная структура.
  • Пятый шаг, если он не достигает 8, то непосредственно сохранить данные в конце связанного списка
  • На шестом шаге вместимость контейнера, наконец, +1.

Расскажите об операции изменения размера хэш-карты

  • Если достигнута максимальная вместимость, вернуться к текущему ведру и больше не расширять вместимость, иначе вместимость будет удвоена, а расширенное ведро будет возвращено;
  • Измените значения атрибутов других переменных-членов в соответствии с расширенным сегментом;
  • Создайте новый расширенный сегмент на основе новой емкости и обновите ссылку на сегмент;
  • Если в исходном сегменте есть элементы, их необходимо перенести;
  • При выполнении переноса элементов необходимо учитывать коллизии элементов и операции переноса красно-черного дерева;
  • В процессе расширения головной узел связанного списка вынимается из исходной корзины один за другим, а хеш-значения всех элементов связанного списка пересчитываются и распределяются;
  • Когда происходит столкновение, добавьте новый добавленный элемент в конец;
  • При копировании элементов необходимо оперировать младшими и старшими битами одновременно.

Поговорим о сравнении ConcurrentHashMap 1.7 и 1.8.

ConcurrentHashMap — это класс из семейства conccurrent.Поскольку он может эффективно поддерживать параллельные операции и широко используется, базовая структура данных классической среды Spring с открытым исходным кодом реализована с использованием ConcurrentHashMap. По сравнению со своим старшим братом HashTable, который тоже потокобезопасен, он уже лучше, поэтому его блокировки более доработаны, вместо того, чтобы добавлять синхронизированные блокировки почти в каждый метод, как HashTable, такие блокировки, несомненно, повлияют на производительность.

Идея 1.7 и 1.8 для достижения потокобезопасности также полностью изменилась, что привело к отказу от оригинальной блокировки сегмента и принятию синхронизации CAS + для обеспечения безопасности параллелизма. Он следует идее версии HashMap одновременно с ней, а нижний слой по-прежнему мыслится как «массив» + связанный список + красно-черное дерево.

  • Вместо использования сегментов используются узлы, а узлы блокируются, чтобы уменьшить степень детализации блокировки.
  • Состояние MOVED разработано. Когда поток 2 все еще помещает данные в процесс изменения размера, поток 2 помогает изменить размер.
  • Используйте 3 операции CAS, чтобы обеспечить атомарность некоторых операций узла, таким образом заменяется блокировка.
  • Разные значения sizeCtl представляют разные значения и играют контролирующую роль.

Разговор о sizeCtl ConcurrentHashMap

  • Отрицательные числа указывают на то, что выполняется инициализация или расширение.
  • -1 означает инициализацию
  • -N означает, что потоки N-1 расширяют емкость
  • Положительное число или 0 указывает на то, что хеш-таблица не была инициализирована.Это значение указывает размер инициализации или следующего расширения, что аналогично концепции порога расширения. Позже вы также можете увидеть, что его значение всегда в 0,75 раза превышает емкость текущего ConcurrentHashMap, что соответствует коэффициенту загрузки.

Расскажите о методе put ConcurrentHashMap.

  • Первый шаг — определить, является ли значение ключа нулевым или нет, и создать исключение, если оно равно нулю.
  • На втором шаге при добавлении пары пар ключ-значение он сначала определит, инициализирован ли массив, хранящий эти пары ключ-значение, и если нет, то инициализирует массив.
  • Третий шаг — определить, какую позицию ставить в массив, вычислив хеш-значение, если эта позиция пуста, добавить ее напрямую (метод блокировки CAS), если она не пуста, то вынести узел в
  • Четвертый шаг, если хеш-значение извлеченного узла ПЕРЕМЕЩЕНО (-1), это означает, что массив в данный момент расширяется и копируется в новый массив, и текущий поток также поможет скопировать
  • Пятый шаг, если узел не пустой и не расширяется, он будет заблокирован через синхронизированный и будет выполнена операция добавления.
  • Шестой шаг, если это связанный список, пройти весь связанный список, пока ключ извлеченного узла не будет сравнен с ключом, который нужно разместить.Если ключи равны и хеш-значения ключей также равны, это означает, что это один и тот же ключ, перезапишите значение, иначе добавьте его в конец связанного списка
  • Шаг седьмой, если это дерево, вызовите метод putTreeVal, чтобы добавить этот элемент в дерево
  • Восьмой шаг, после того, как добавление будет завершено, определит, сколько узлов есть в узле (обратите внимание на число перед добавлением), если оно достигает более 8, то вызовите метод treeifyBin, чтобы попытаться преобразовать связанный список в дерево , или количество расширений

конец

Это некоторые основные вопросы для собеседования, многие из которых, конечно, не обязательно полны, но если на них можно ответить, на самом деле основа Java достаточно прочная.

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всенастоящий порошок.

Творить нелегко. Ваша поддержка и признание — самая большая мотивация для моего творчества. Увидимся в следующей статье.

Поиск в WeChat "Жизнь программы шестиимпульсного Excalibur" Ответить 888 Я нашел для вас много информации