👍1
Comparator и Comparable. В чем разница? 🤓
Ответ:
Оба интерфейса используются для сравнения и сортировки объектов.
Comparable определяет естественный порядок сортировки объектов класса. Он содержит один метод compareTo(T o) и реализуется внутри самого класса, который нужно сортировать.
Comparator — это отдельный класс, реализующий интерфейс с методом compare(T o1, T o2). Он определяет альтернативный (внешний) порядок сортировки, не изменяя исходный класс.
Можно создавать множество Comparator для разных видов сортировки.
#собеседование
Ответ:
Comparable определяет естественный порядок сортировки объектов класса. Он содержит один метод compareTo(T o) и реализуется внутри самого класса, который нужно сортировать.
Comparator — это отдельный класс, реализующий интерфейс с методом compare(T o1, T o2). Он определяет альтернативный (внешний) порядок сортировки, не изменяя исходный класс.
Можно создавать множество Comparator для разных видов сортировки.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
История IT-технологий сегодня —31 января
ℹ️ Кто родился в этот день
Гвидо ван Россум (нид. Guido van Rossum; род. 31 января 1956, Гаага, Нидерланды) — голландский программист, прежде всего известный как автор языка программирования Python. Среди разработчиков Python Гвидо известен как «великодушный пожизненный диктатор» проекта, что означает, что он продолжает наблюдать за процессом разработки Python, принимая окончательные решения, когда это необходимо. С июля 2018 года Гвидо ушёл в постоянный отпуск от диктаторства, оставив за собой право быть обычным разработчиком. До разработки Python участвовал в проекте по написанию языка для обучения программированию — ABC. Лауреат «Free Software Award» 2001 года. Покинув в декабре 2012 года корпорацию Google, с 2013 года работал в компании Dropbox Inc, выйдя на пенсию в 2019, а в ноябре 2020 года присоединился к одному из отделов корпорации Microsoft.
Ирма М. Уайман (31 января 1928 г. — 17 ноября 2015 г.) — одна из первых инженеров-программистов и первая женщина, ставшая вице-президентом компании Honeywell, Inc. Она была преподавателем системного мышления и первой женщиной-главным ИТ-директором Honeywell, Inc., которая тогда входила в список Fortune 100.
🌐 Знаковые события
1958 — запущен «Эксплорер-1», первый американский спутник.
#Biography #Birth_Date #Events #31Января
Гвидо ван Россум (нид. Guido van Rossum; род. 31 января 1956, Гаага, Нидерланды) — голландский программист, прежде всего известный как автор языка программирования Python. Среди разработчиков Python Гвидо известен как «великодушный пожизненный диктатор» проекта, что означает, что он продолжает наблюдать за процессом разработки Python, принимая окончательные решения, когда это необходимо. С июля 2018 года Гвидо ушёл в постоянный отпуск от диктаторства, оставив за собой право быть обычным разработчиком. До разработки Python участвовал в проекте по написанию языка для обучения программированию — ABC. Лауреат «Free Software Award» 2001 года. Покинув в декабре 2012 года корпорацию Google, с 2013 года работал в компании Dropbox Inc, выйдя на пенсию в 2019, а в ноябре 2020 года присоединился к одному из отделов корпорации Microsoft.
Ирма М. Уайман (31 января 1928 г. — 17 ноября 2015 г.) — одна из первых инженеров-программистов и первая женщина, ставшая вице-президентом компании Honeywell, Inc. Она была преподавателем системного мышления и первой женщиной-главным ИТ-директором Honeywell, Inc., которая тогда входила в список Fortune 100.
1958 — запущен «Эксплорер-1», первый американский спутник.
#Biography #Birth_Date #Events #31Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
С 24.01 по 30.01
Предыдущий пост(С 17.12 по 23.01)
Воскресный мотивационный пост:
Потом не существует. Есть только сегодня и никогда
Запись встреч/видео:
3. Data Access Layer: осознанный выбор между JPA, JDBC и jOOQ
Обучающие статьи:
Java:
Раздел 7. Алгоритмы
Глава 4: Эффективный поиск. Бинарный и не только
Модификации и родственные методы
Практика
Глава 5: Рекурсия, деревья и введение в динамическое программирование
Принцип рекурсии и её опасности
Рекурсия на практике: обход деревьев
От рекурсии к динамическому программированию
Полезные статьи и видео:
Как компьютер понимает Языки программирования: история о том, как ваш код превращается в нули и единицы
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(С 17.12 по 23.01)
Воскресный мотивационный пост:
Потом не существует. Есть только сегодня и никогда
Запись встреч/видео:
3. Data Access Layer: осознанный выбор между JPA, JDBC и jOOQ
Обучающие статьи:
Java:
Раздел 7. Алгоритмы
Глава 4: Эффективный поиск. Бинарный и не только
Модификации и родственные методы
Практика
Глава 5: Рекурсия, деревья и введение в динамическое программирование
Принцип рекурсии и её опасности
Рекурсия на практике: обход деревьев
От рекурсии к динамическому программированию
Полезные статьи и видео:
Как компьютер понимает Языки программирования: история о том, как ваш код превращается в нули и единицы
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍2
История IT-технологий сегодня — 01 Февраля
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
1982 — компания Intel выпустила первый Intel 80286 — 16-разрядный процессор второго поколения архитектуры x86.
#Biography #Birth_Date #Events #01февраля
Не нашел(
1982 — компания Intel выпустила первый Intel 80286 — 16-разрядный процессор второго поколения архитектуры x86.
#Biography #Birth_Date #Events #01февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
А вы читаете этот канал? Давайте посчитаем сколько нас из 800, реально заходят и читают посты?
Anonymous Poll
81%
Я читаю!
9%
Я не читаю, но голос оставлю)
9%
Я есть Грут
🔥4
Ждете новое видео? Загружается уже)
Anonymous Poll
91%
Да жду!
0%
Не, оставь себе
5%
Перестань записывать всякое гомно!
5%
Что я тут делаю?
🔥1
4. Spring Boot Actuator: телеметрия вашего микросервиса
В этом видео мы превращаем OrderHub из чёрного ящика в наблюдаемую production-систему.
Spring Boot Actuator — это не просто библиотека, а стандартный Runtime API, через который микросервис общается с платформой (Kubernetes, мониторинг, SRE).
Что вы узнаете:
🔹 Health как контракт с оркестратором
- Как Kubernetes использует /health для liveness и readiness probes
- Иерархия HealthIndicators: от диска до бизнес-логики
- Что происходит, когда база данных "падает"
🔹 Metrics — язык общения с платформой
- Как Micrometer и Actuator работают вместе
- Four Golden Signals для SRE: latency, traffic, errors, saturation
- Почему метрики должны быть с тегами
🔹 Info — паспорт сервиса в распределённой системе
- Immutable metadata для быстрой диагностики инцидентов
🔹 Advanced endpoints — инструменты последней линии обороны
- Для чего и когда испольщовать /env, /heapdump, /threaddump
- Динамическое управление логированием через /loggers
- Почему эти инструменты опасны в неверных руках
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
В этом видео мы превращаем OrderHub из чёрного ящика в наблюдаемую production-систему.
Spring Boot Actuator — это не просто библиотека, а стандартный Runtime API, через который микросервис общается с платформой (Kubernetes, мониторинг, SRE).
Что вы узнаете:
🔹 Health как контракт с оркестратором
- Как Kubernetes использует /health для liveness и readiness probes
- Иерархия HealthIndicators: от диска до бизнес-логики
- Что происходит, когда база данных "падает"
🔹 Metrics — язык общения с платформой
- Как Micrometer и Actuator работают вместе
- Four Golden Signals для SRE: latency, traffic, errors, saturation
- Почему метрики должны быть с тегами
🔹 Info — паспорт сервиса в распределённой системе
- Immutable metadata для быстрой диагностики инцидентов
🔹 Advanced endpoints — инструменты последней линии обороны
- Для чего и когда испольщовать /env, /heapdump, /threaddump
- Динамическое управление логированием через /loggers
- Почему эти инструменты опасны в неверных руках
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
Java for Beginner
4. Spring Boot Actuator: телеметрия вашего микросервиса В этом видео мы превращаем OrderHub из чёрного ящика в наблюдаемую production-систему. Spring Boot Actuator — это не просто библиотека, а стандартный Runtime API, через который микросервис общается с…
Ссылку на рутьюб обновил) Извините, интернет - 💩
Please open Telegram to view this post
VIEW IN TELEGRAM
🤓2
История IT-технологий сегодня — 02 Февраля
ℹ️ Кто родился в этот день
Джон Генри Холланд (англ. John Henry Holland; 2 февраля 1929, Форт-Уэйн — 9 августа 2015, Анн-Арбор) — американский учёный, профессор психологии, профессор электротехники и информатики в Мичиганском университете, Анн-Арбор. Один из первых учёных, начавших изучать сложные системы и нелинейную науку; известен как отец генетических алгоритмов.
Ральф Чарльз Меркл (англ. Ralph Charles Merkle; родился 2 февраля 1952, Беркли, Калифорния, США) — американский криптограф, один из создателей криптографии с открытым ключом (схема Меркла, деревья Меркла и др.); деревья Меркла являются базовым примитивом в блокчейнах, системах проверки целостности данных, файловых системах и ряде протоколов безопасности.
🌐 Знаковые события
2000 – первая в Европе цифровая кинопроекция (Париж), реализованная Филиппом Бинаном с использованием технологии DLP CINEMA, разработанной компанией Texas Instruments .
#Biography #Birth_Date #Events #02февраля
Джон Генри Холланд (англ. John Henry Holland; 2 февраля 1929, Форт-Уэйн — 9 августа 2015, Анн-Арбор) — американский учёный, профессор психологии, профессор электротехники и информатики в Мичиганском университете, Анн-Арбор. Один из первых учёных, начавших изучать сложные системы и нелинейную науку; известен как отец генетических алгоритмов.
Ральф Чарльз Меркл (англ. Ralph Charles Merkle; родился 2 февраля 1952, Беркли, Калифорния, США) — американский криптограф, один из создателей криптографии с открытым ключом (схема Меркла, деревья Меркла и др.); деревья Меркла являются базовым примитивом в блокчейнах, системах проверки целостности данных, файловых системах и ряде протоколов безопасности.
2000 – первая в Европе цифровая кинопроекция (Париж), реализованная Филиппом Бинаном с использованием технологии DLP CINEMA, разработанной компанией Texas Instruments .
#Biography #Birth_Date #Events #02февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Раздел 7. Алгоритмы
Глава 5: Рекурсия, деревья и введение в динамическое программирование
Практическое применение рекурсии в библиотечной системе
Цели:
Освоить принципы работы с древовидными структурами
Научиться применять рекурсию для обхода иерархических данных
Сравнить рекурсивные и итеративные подходы
Понять оптимизацию рекурсии через мемоизацию
Часть 1: Моделирование древовидной структуры жанров
Постановка задачи:
В нашей библиотеке жанры книг образуют иерархию.
Например:
Литература (корень)
Художественная литература
Фантастика
Научная фантастика
Фэнтези
Нехудожественная литература
Вам нужно: Создать структуру данных, которая позволит хранить такую иерархию.
Шаг 1.1: Создайте класс Genre
Что нужно сделать:
Определите, какие поля понадобятся для хранения:
Название жанра
Список поджанров (дочерние элементы)
Список книг, относящихся к этому жанру
Реализуйте:
Конструктор, принимающий название жанра
Методы для добавления поджанра и книги
Геттеры для доступа к данным
Вопрос для размышления: Почему важно, чтобы поджанры хранились как список объектов Genre?
Шаг 1.2: Свяжите книги с жанрами
Что нужно сделать:
Обновите класс Book:
Добавьте поле для хранения основного жанра книги
Измените конструктор для установки жанра
Подумайте: Может ли книга принадлежать к нескольким жанрам? Как это реализовать?
Шаг 1.3: Построение дерева жанров
Практическое задание:
В классе Library создайте метод initGenres(), который:
Создаёт корневой жанр "Литература"
Добавляет 3-4 уровня вложенности жанров
Распределяет существующие книги по соответствующим жанрам
Проверка: Убедитесь, что у вас получилось дерево глубиной не менее 4 уровней.
Часть 2: Рекурсивный подсчёт книг в жанре
Задача: Напишите метод, который считает все книги в жанре и его поджанрах
Рекурсия работает так:
Базовый случай: если у жанра нет поджанров, возвращаем количество его книг
Рекурсивный случай: суммируем книги текущего жанра + рекурсивно вызываем метод для каждого поджанра
Пример:
Шаг 2.1: Реализуйте метод countBooksRecursive()
Что нужно сделать:
Добавьте метод в класс Genre
Реализуйте рекурсивный подсчёт по описанному алгоритму
Протестируйте на разных уровнях дерева
Контрольные вопросы:
Что произойдёт, если в дереве будет циклическая ссылка?
Какова максимальная глубина рекурсии для вашего дерева?
Часть 3: Сравнение рекурсивного и итеративного обхода
Задача: Вывести структуру дерева жанров двумя способами
Шаг 3.1: Рекурсивный обход (Pre-order)
Алгоритм:
Обработать текущий узел (вывести информацию)
Рекурсивно обработать все дочерние узлы
Что нужно сделать:
Реализуйте метод printTreeRecursive(Genre genre, int depth), где depth используется для создания отступов при выводе.
Шаг 3.2: Итеративный обход с использованием стека
Можно эмулировать рекурсию с помощью стека:
Помещаем корневой элемент в стек
Пока стек не пуст:
Извлекаем элемент
Обрабатываем его
Добавляем в стек его детей
Что нужно сделать:
Реализуйте метод printTreeIterative(Genre root) с использованием Stack<Genre>.
Вопрос: Почему детей нужно добавлять в стек в обратном порядке?
Шаг 3.3: Сравнение подходов
Практическое задание:
Создайте дерево глубиной 10 уровней
Замерьте время выполнения обоих методов
Ответьте на вопросы:
Какой подход читаемее?
Какой безопаснее для глубоких деревьев?
Когда стоит использовать каждый из них?
#Java #для_новичков #beginner #algorithm #recursion #практика
Глава 5: Рекурсия, деревья и введение в динамическое программирование
Практическое применение рекурсии в библиотечной системе
Цели:
Освоить принципы работы с древовидными структурами
Научиться применять рекурсию для обхода иерархических данных
Сравнить рекурсивные и итеративные подходы
Понять оптимизацию рекурсии через мемоизацию
Часть 1: Моделирование древовидной структуры жанров
Постановка задачи:
В нашей библиотеке жанры книг образуют иерархию.
Например:
Литература (корень)
Художественная литература
Фантастика
Научная фантастика
Фэнтези
Нехудожественная литература
Вам нужно: Создать структуру данных, которая позволит хранить такую иерархию.
Шаг 1.1: Создайте класс Genre
Что нужно сделать:
Определите, какие поля понадобятся для хранения:
Название жанра
Список поджанров (дочерние элементы)
Список книг, относящихся к этому жанру
Реализуйте:
Конструктор, принимающий название жанра
Методы для добавления поджанра и книги
Геттеры для доступа к данным
Вопрос для размышления: Почему важно, чтобы поджанры хранились как список объектов Genre?
Шаг 1.2: Свяжите книги с жанрами
Что нужно сделать:
Обновите класс Book:
Добавьте поле для хранения основного жанра книги
Измените конструктор для установки жанра
Подумайте: Может ли книга принадлежать к нескольким жанрам? Как это реализовать?
Шаг 1.3: Построение дерева жанров
Практическое задание:
В классе Library создайте метод initGenres(), который:
Создаёт корневой жанр "Литература"
Добавляет 3-4 уровня вложенности жанров
Распределяет существующие книги по соответствующим жанрам
Проверка: Убедитесь, что у вас получилось дерево глубиной не менее 4 уровней.
Часть 2: Рекурсивный подсчёт книг в жанре
Задача: Напишите метод, который считает все книги в жанре и его поджанрах
Рекурсия работает так:
Базовый случай: если у жанра нет поджанров, возвращаем количество его книг
Рекурсивный случай: суммируем книги текущего жанра + рекурсивно вызываем метод для каждого поджанра
Пример:
Книг в "Фантастике" =
книги в "Фантастике" +
книги в "Научной фантастике" +
книги в "Фэнтези"
Шаг 2.1: Реализуйте метод countBooksRecursive()
Что нужно сделать:
Добавьте метод в класс Genre
Реализуйте рекурсивный подсчёт по описанному алгоритму
Протестируйте на разных уровнях дерева
Контрольные вопросы:
Что произойдёт, если в дереве будет циклическая ссылка?
Какова максимальная глубина рекурсии для вашего дерева?
Часть 3: Сравнение рекурсивного и итеративного обхода
Задача: Вывести структуру дерева жанров двумя способами
Шаг 3.1: Рекурсивный обход (Pre-order)
Алгоритм:
Обработать текущий узел (вывести информацию)
Рекурсивно обработать все дочерние узлы
Что нужно сделать:
Реализуйте метод printTreeRecursive(Genre genre, int depth), где depth используется для создания отступов при выводе.
Шаг 3.2: Итеративный обход с использованием стека
Можно эмулировать рекурсию с помощью стека:
Помещаем корневой элемент в стек
Пока стек не пуст:
Извлекаем элемент
Обрабатываем его
Добавляем в стек его детей
Что нужно сделать:
Реализуйте метод printTreeIterative(Genre root) с использованием Stack<Genre>.
Вопрос: Почему детей нужно добавлять в стек в обратном порядке?
Шаг 3.3: Сравнение подходов
Практическое задание:
Создайте дерево глубиной 10 уровней
Замерьте время выполнения обоих методов
Ответьте на вопросы:
Какой подход читаемее?
Какой безопаснее для глубоких деревьев?
Когда стоит использовать каждый из них?
#Java #для_новичков #beginner #algorithm #recursion #практика
👍3
Часть 4: Числа Фибоначчи - три подхода
Задача: Вычислить n-ное число Фибоначчи
Определение:
F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2)
Шаг 4.1: Наивная рекурсия
Что нужно сделать:
Реализуйте метод fibRecursive(int n) по определению.
Анализ проблемы:
Нарисуйте дерево вызовов для n=5. Сколько раз вычисляется F(2)? F(3)?
Задание: Замерьте время выполнения для n=40. Почему это так долго?
Шаг 4.2: Мемоизация (Top-down динамическое программирование)
Идея: Сохранять уже вычисленные значения, чтобы не вычислять их повторно.
Что нужно сделать:
Создайте HashMap<Integer, Long> для хранения вычисленных значений
Измените рекурсивную функцию так, чтобы она:
Проверяла, нет ли значения в кэше
Сохраняла новое значение после вычисления
Вопрос: Как изменилось дерево вызовов?
Шаг 4.3: Итеративное решение (Bottom-up)
Алгоритм:
Если n <= 1: вернуть n
Иначе: последовательно вычислить все числа от 2 до n
Что нужно сделать:
Реализуйте метод fibIterative(int n) без рекурсии.
Задание: Сравните производительность всех трёх методов для n=50.
Итоговые задания
Задание 1: Рефакторинг
Перепишите один из рекурсивных методов в итеративный. Объясните, что изменилось в сложности кода.
Задание 2: Оптимизация
Добавьте проверку на циклические ссылки в дереве жанров. Что произойдёт без этой проверки?
Задание 3: Эксперимент
Создайте глубокое дерево (20+ уровней). Протестируйте оба метода обхода. При какой глубине возникает StackOverflowError?
Задание 4: Документация
Напишите комментарии к методам, объясняющие:
Сложность алгоритма (Big O)
Ограничения (максимальная глубина)
Рекомендации по использованию
#Java #для_новичков #beginner #algorithm #recursion #практика
Задача: Вычислить n-ное число Фибоначчи
Определение:
F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2)
Шаг 4.1: Наивная рекурсия
Что нужно сделать:
Реализуйте метод fibRecursive(int n) по определению.
Анализ проблемы:
Нарисуйте дерево вызовов для n=5. Сколько раз вычисляется F(2)? F(3)?
Задание: Замерьте время выполнения для n=40. Почему это так долго?
Шаг 4.2: Мемоизация (Top-down динамическое программирование)
Идея: Сохранять уже вычисленные значения, чтобы не вычислять их повторно.
Что нужно сделать:
Создайте HashMap<Integer, Long> для хранения вычисленных значений
Измените рекурсивную функцию так, чтобы она:
Проверяла, нет ли значения в кэше
Сохраняла новое значение после вычисления
Вопрос: Как изменилось дерево вызовов?
Шаг 4.3: Итеративное решение (Bottom-up)
Алгоритм:
Если n <= 1: вернуть n
Иначе: последовательно вычислить все числа от 2 до n
Что нужно сделать:
Реализуйте метод fibIterative(int n) без рекурсии.
Задание: Сравните производительность всех трёх методов для n=50.
Итоговые задания
Задание 1: Рефакторинг
Перепишите один из рекурсивных методов в итеративный. Объясните, что изменилось в сложности кода.
Задание 2: Оптимизация
Добавьте проверку на циклические ссылки в дереве жанров. Что произойдёт без этой проверки?
Задание 3: Эксперимент
Создайте глубокое дерево (20+ уровней). Протестируйте оба метода обхода. При какой глубине возникает StackOverflowError?
Задание 4: Документация
Напишите комментарии к методам, объясняющие:
Сложность алгоритма (Big O)
Ограничения (максимальная глубина)
Рекомендации по использованию
#Java #для_новичков #beginner #algorithm #recursion #практика
👍4
Что выведет код?
#Tasks
import java.util.Arrays;
import java.util.Comparator;
public class Task020226 {
public static void main(String[] args) {
Integer[] arr = {5, 2, 8, 1, 3};
Comparator<Integer> comp = (a, b) -> {
System.out.print(a + ":" + b + " ");
return a - b;
};
Arrays.sort(arr, comp);
System.out.println("\n" + Arrays.toString(arr));
}
}
#Tasks
👍1
Что такое String Pool? 🤓
Ответ:
String Pool (пул строк) — это специальная область в Heap (куче) памяти JVM, предназначенная для хранения уникальных литералов строк.
Когда создается строковый литерал (например, String s = "hello";), JVM ищет такую же строку в пуле. Если находит, то возвращает ссылку на существующий объект, если нет — создает новый объект в пуле. Это позволяет экономить память.
Оператор new String("hello") всегда создает новый объект в куче вне пула, даже если такая строка уже есть в пуле.
#собеседование
Ответ:
String Pool (пул строк)
Когда создается строковый литерал (например, String s = "hello";), JVM ищет такую же строку в пуле. Если находит, то возвращает ссылку на существующий объект, если нет — создает новый объект в пуле. Это позволяет экономить память.
Оператор new String("hello") всегда создает новый объект в куче вне пула, даже если такая строка уже есть в пуле.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История IT-технологий сегодня — 03 Февраля
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
1966 — АМС «Луна-9», запущенная 31 января, впервые в мире осуществила посадку на поверхность Луны в районе Океана Бурь и передала первую лунную фотопанораму.
#Biography #Birth_Date #Events #03февраля
Не нашел(
1966 — АМС «Луна-9», запущенная 31 января, впервые в мире осуществила посадку на поверхность Луны в районе Океана Бурь и передала первую лунную фотопанораму.
#Biography #Birth_Date #Events #03февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
[Совет по Java #001]
Тема: Всегда переопределяйте equals() и hashCode() вместе, особенно для сущностей, которые будут храниться в HashSet или использоваться как ключи в HashMap.
Проблема: Нарушение ключевого контракта (contract) между методами equals() и hashCode().
Согласно спецификации Java, если два объекта равны согласно методу equals(Object), то вызов метода hashCode() для каждого из них должен возвращать одно и то же целочисленное значение.
Обратное утверждение не является обязательным: объекты с одинаковым хэш-кодом могут быть не равны (коллизия). Если разработчик переопределяет только equals(), основываясь, например, на внутренних полях объекта, но оставляет исходный hashCode() (который обычно возвращает уникальный код на основе адреса в памяти), то такие объекты, будучи логически равными, будут иметь разные хэш-коды. Это приведет к катастрофическому нарушению работы хэш-коллекций (HashSet, HashMap, ConcurrentHashMap).
Объекты не будут найдены в коллекции, дубликаты будут добавляться в HashSet, а операции с HashMap дадут непредсказуемые и ошибочные результаты. Такие ошибки трудно отлаживать, так как поведение становится недетерминированным.
Решение: Всегда совместное переопределение обоих методов, гарантирующее соблюдение их общего контракта. Реализация должна основываться на одном и том же наборе значимых (significant) полей объекта. Для вычисления хэш-кода рекомендуется использовать алгоритм, дающий хорошее распределение.
Объяснение: Метод Objects.hash(Object...) предоставляет удобную и эффективную реализацию хэш-функции, основанную на содержимом переданных полей.
Важно, что в вычислении участвуют те же поля (id и name), которые используются в equals(). Класс объявлен как final, чтобы избежать наследования и потенциального нарушения симметричности контракта equals() (проблема сравнения объекта родительского класса с объектом дочернего). Использование final полей делает класс неизменяемым (immutable), что дополнительно гарантирует стабильность хэш-кода во времени — ключевое требование для корректной работы в качестве ключа в хэш-таблицах. Нарушение этого требования (изменение поля, участвующего в hashCode(), после помещения объекта в коллекцию) приведет к потере объекта в структуре данных.
#Java #советы
Тема: Всегда переопределяйте equals() и hashCode() вместе, особенно для сущностей, которые будут храниться в HashSet или использоваться как ключи в HashMap.
Проблема: Нарушение ключевого контракта (contract) между методами equals() и hashCode().
Согласно спецификации Java, если два объекта равны согласно методу equals(Object), то вызов метода hashCode() для каждого из них должен возвращать одно и то же целочисленное значение.
Обратное утверждение не является обязательным: объекты с одинаковым хэш-кодом могут быть не равны (коллизия). Если разработчик переопределяет только equals(), основываясь, например, на внутренних полях объекта, но оставляет исходный hashCode() (который обычно возвращает уникальный код на основе адреса в памяти), то такие объекты, будучи логически равными, будут иметь разные хэш-коды. Это приведет к катастрофическому нарушению работы хэш-коллекций (HashSet, HashMap, ConcurrentHashMap).
Объекты не будут найдены в коллекции, дубликаты будут добавляться в HashSet, а операции с HashMap дадут непредсказуемые и ошибочные результаты. Такие ошибки трудно отлаживать, так как поведение становится недетерминированным.
Решение: Всегда совместное переопределение обоих методов, гарантирующее соблюдение их общего контракта. Реализация должна основываться на одном и том же наборе значимых (significant) полей объекта. Для вычисления хэш-кода рекомендуется использовать алгоритм, дающий хорошее распределение.
import java.util.Objects;
public final class Entity {
private final Long id;
private final String name;
public Entity(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true; // Проверка на идентичность ссылок
if (o == null || getClass() != o.getClass()) return false; // Проверка класса
Entity entity = (Entity) o;
// Сравнение по значимым полям. Используем Objects.equals() для null-safe сравнения.
return Objects.equals(id, entity.id) &&
Objects.equals(name, entity.name);
}
@Override
public int hashCode() {
// Используем хэш-функцию на основе тех же полей, что и в equals()
return Objects.hash(id, name);
}
}
Объяснение: Метод Objects.hash(Object...) предоставляет удобную и эффективную реализацию хэш-функции, основанную на содержимом переданных полей.
Важно, что в вычислении участвуют те же поля (id и name), которые используются в equals(). Класс объявлен как final, чтобы избежать наследования и потенциального нарушения симметричности контракта equals() (проблема сравнения объекта родительского класса с объектом дочернего). Использование final полей делает класс неизменяемым (immutable), что дополнительно гарантирует стабильность хэш-кода во времени — ключевое требование для корректной работы в качестве ключа в хэш-таблицах. Нарушение этого требования (изменение поля, участвующего в hashCode(), после помещения объекта в коллекцию) приведет к потере объекта в структуре данных.
#Java #советы
👍3🔥2🆒1
Что выведет код?
#Tasks
import java.util.HashSet;
public class Task030226 {
public static void main(String[] args) {
HashSet<Item030226> set = new HashSet<>();
Item030226 item1 = new Item030226(1, "apple");
Item030226 item2 = new Item030226(1, "apple");
set.add(item1);
item1.id = 2;
set.add(item2);
System.out.println(set.size());
System.out.println(set.contains(item1));
System.out.println(set.contains(item2));
}
static class Item030226 {
int id;
String name;
Item030226(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item030226 item = (Item030226) o;
return id == item.id && name.equals(item.name);
}
@Override
public int hashCode() {
return id + name.hashCode();
}
}
}
#Tasks
👍1
👍1
Что такое конструктор? Можно ли наследовать конструктор? 🤓
Ответ:
Конструктор — это специальный метод класса, который вызывается при создании нового объекта.
Его имя должно совпадать с именем класса, и у него нет возвращаемого типа. Конструкторы не наследуются.
При создании объекта класса-потомка всегда вызывается конструктор его родительского класса (явно через super(...) или неявно, вызывается конструктор по умолчанию super()).
Если в родительском классе нет конструктора по умолчанию, в классе-потомке обязательно нужно явно вызвать один из существующих.
#собеседование
Ответ:
Конструктор
Его имя должно совпадать с именем класса, и у него нет возвращаемого типа. Конструкторы не наследуются.
При создании объекта класса-потомка всегда вызывается конструктор его родительского класса (явно через super(...) или неявно, вызывается конструктор по умолчанию super()).
Если в родительском классе нет конструктора по умолчанию, в классе-потомке обязательно нужно явно вызвать один из существующих.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4