Что такое hashmap
Перейти к содержимому

Что такое hashmap

  • автор:

HashMap

При работе с массивами я сравнивал их с коробочками. Слово HashMap содержит слово map — карта. Только это не пытайтесь найти сходство с картами в географическом атласе, с гуглокартами, с Яндекс.Картами или, на худой конец, с игральными картами. Это карточка в картотеке. Вы заполняете карточки какими-то данными и кладёте их в ящик. Если вы содержите гостиницу для котов, то скорее всего вы занесёте в карточку имя кота, возраст и т.п.

Класс HashMap использует хеш-таблицу для хранения карточки, обеспечивая быстрое время выполнения запросов get() и put() при больших наборах. Класс реализует интерфейс Map (хранение данных в виде пар ключ/значение). Ключи и значения могут быть любых типов, в том числе и null. При этом все ключи обязательно должны быть уникальны, а значения могут повторяться. Данная реализация не гарантирует порядка элементов.

Общий вид HashMap:

 // K - это Key (ключ), V - Value (значение) class HashMap

Объявить можно следующим образом:

 Map hashMap = new HashMap(); // или так Map hashMap = new HashMap(); 

По умолчанию при использовании пустого конструктора создается картотека ёмкостью из 16 ячеек. При необходимости ёмкость увеличивается, вам не надо об этом задумываться.

HashMap

Вы можете указать свои ёмкость и коэффициент загрузки, используя конструкторы HashMap(capacity) и HashMap(capacity, loadFactor). Максимальная ёмкость, которую вы сможете установить, равна половине максимального значения int (1073741824).

Добавление элементов происходит при помощи метода put(K key, V value). Вам надо указать ключ и его значение.

 hashMap.put("0", "Васька"); 
 hashMap.size(); 

Проверяем ключ и значение на наличие:

 hashMap.containsKey("0"); hashMap.containsValue("Васька"); 

Выбираем все ключи:

 for (String key : hashMap.keySet())

Выбираем все значения:

 for (int value : hashMap.values())

Выбираем все ключи и значения одновременно:

 for (Map.Entry entry : hashMap.entrySet())

Пример первый

 // Создадим хеш-карточку Map hashMap = new HashMap<>(); // Помещаем данные на карточку hashMap.put("Васька", 5); hashMap.put("Мурзик", 8); hashMap.put("Рыжик", 12); hashMap.put("Барсик", 5); // Получаем набор элементов Set set = hashMap.entrySet(); // Отобразим набор for (Map.Entry me : set) < System.out.print(me.getKey() + ": "); System.out.println(me.getValue()); >// Добавляем значение int value = hashMap.get("Рыжик"); hashMap.put("Рыжик", value + 3); System.out.println("У Рыжика стало " + hashMap.get("Рыжик")); 

Если вы посмотрите на результат, то увидите, что данные находятся не в том порядке, в котором вы заносили. Второй важный момент — если в карточке уже существует какой-то ключ, то если вы помещаете в него новое значение, то ключ перезаписывается, а не заносится новый ключ.

В древних версиях Java приходилось добавлять новые значения следующим образом.

 hashMap.put("Мурзик", new Integer(8)); // или hashMap.put("Мурзик", Integer.valueOf(8)); 

Потом Java поумнела и стала самостоятельно переводить число типа int в объект Integer. Но это не решило основной проблемы — использование объектов очень сильно сказывается на потреблении памяти. Поэтому в Android были предложены аналоги этого класса (см. ниже). Ключом в Map может быть любой объект, у которого корректно реализованы методы hashCode() и equals().

Пример второй

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

 Random random = new Random(36); Map hashMap = new HashMap<>(); for (int i = 0; i < 100; i++)< // Создадим число от 0 до 10 int number = random.nextInt(10); Integer frequency = hashMap.get(number); hashMap.put(number, frequency == null ? 1 : frequency + 1); >System.out.println(hashMap); 

Метод get() возвращает null, если ключ отсутствует, т.е число было сгенерировано впервые или в противном случае метод возвращает для данного ключа ассоциированное значение, которое увеличивается на единицу.

Пример третий

Пример для закрепления материала. Поработаем с объектами классов. Нужно самостоятельно создать класс Pet и его наследников Cat, Dog, Parrot.

Создадим отображение из домашних животных, где в качестве ключа выступает строка, а в качестве значения класс Pet.

 Map hashMap = new HashMap<>(); hashMap.put("Кот", new Cat("Мурзик")); hashMap.put("Собака", new Dog("Бобик")); hashMap.put("Попугай", new Parrot("Кеша")); System.out.println(hashMap); Pet cat = hashMap.get("Кот"); System.out.println(cat); System.out.println(hashMap.containsKey("Кот")); System.out.println(hashMap.containsValue(cat)); 

Многомерные отображения

Контейнеры Map могут расширяться до нескольких измерений, достаточно создать контейнер Map, значениями которого являются контейнеры Map (значениями которых могут быть другие контейнеры). Предположим, вы хотите хранить информацию о владельцах домашних животных, у каждого из которых может быть несколько любимцев. Для этого нам нужно создать контейнер Map>.

 Map> personMap = new HashMap<>(); personMap.put(new Person("Иван"), Arrays.asList(new Cat("Барсик"), new Cat("Мурзик"))); personMap.put(new Person("Маша"), Arrays.asList(new Cat("Васька"), new Dog("Бобик"))); personMap.put(new Person("Ирина"), Arrays.asList(new Cat("Рыжик"), new Dog("Шарик"), new Parrot("Гоша"))); System.out.println("personMap: " + personMap); System.out.println("personMap.keySet(): " + personMap.keySet()); for(Person person : personMap.keySet()) < System.out.println(person + " имеет"); for (Pet pet : personMap.get(person))< System.out.println(" " + pet); >> 

Метод keySet() возвращает контейнер Set, содержащий все ключи из personMap, который используется в цикле для перебора элементов Map.

Sparse arrays — аналог в Android

Разработчик Android посчитали, что HashMap не слишком оптимизирован для мобильных устройств и предложили свой вариант в виде специальных массивов. Данные классы являются родными для Android, но не являются частью Java. Очень рекомендуют использовать именно Android-классы. Не все программисты знают об этих аналогах, а также классический код может встретиться в различных Java-библиотеках. Если вы увидите такой код, то заменить его на нужный. Ниже представлена таблица для замены.

HashMap Array class
HashMap

ArrayMap
HashMap

SparseArray
HashMap

SparseBooleanArray
HashMap

SparseIntArray
HashMap

SparseLongArray
HashMap

LongSparseArray

Существует ещё класс HashTable, который очень похож в использовании как и HashMap.

Язык программирования Rust

Хранение ключей со связанными значениями в HashMap

Последняя коллекция, которую мы рассмотрим, будет hash map (хеш-карта). Тип HashMap хранит ключи типа K на значения типа V . Данная структура организует и хранит данные с помощью функции хеширования. Во множестве языков программирования реализована данная структура, но часто с разными наименованиями: такими как hash, map, object, hash table, dictionary или ассоциативный массив.

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

В этом разделе мы рассмотрим базовый API хеш-карт. Остальной набор полезных функций скрывается в объявлении типа HashMap . Как и прежде, советуем обратиться к документации по стандартной библиотеке для получения дополнительной информации.

Создание новой хеш-карты

Создать пустую хеш-карту можно с помощью new , а добавить в неё элементы — с помощью insert . В листинге 8-20 мы отслеживаем счёт двух команд, синей Blue и жёлтой Yellow. Синяя команда набрала 10 очков, а жёлтая команда — 50.

fn main()  use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); > 

Листинг 8-20: Создание новой хеш-карты и вставка в неё пары ключей и значений

Обратите внимание, что нужно сначала указать строку use std::collections::HashMap; для её подключения из коллекций стандартной библиотеки. Из трёх коллекций данная является наименее используемой, поэтому она не подключается в область видимости функцией автоматического импорта (prelude). Хеш-карты также имеют меньшую поддержку со стороны стандартной библиотеки; например, нет встроенного макроса для их конструирования.

Подобно векторам, хеш-карты хранят свои данные в куче. Здесь тип HashMap имеет в качестве типа ключей String , а в качестве типа значений тип i32 . Как и векторы, HashMap однородны: все ключи должны иметь одинаковый тип и все значения должны иметь тоже одинаковый тип.

Доступ к данным в HashMap

Мы можем получить значение из HashMap по ключу, с помощью метода get , как показано в листинге 8-21.

fn main()  use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); let team_name = String::from("Blue"); let score = scores.get(&team_name).copied().unwrap_or(0); > 

Листинг 8-21: Доступ к очкам команды "Blue", которые хранятся в хеш-карте

Здесь score будет иметь количество очков, связанное с командой "Blue", результат будет 10 . Метод get возвращает Option ; если для какого-то ключа нет значения в HashMap, get вернёт None . Из-за такого подхода программе следует обрабатывать Option , вызывая copied для получения Option вместо Option , затем unwrap_or для установки score в ноль, если scores не содержит данных по этому ключу.

Мы можем перебирать каждую пару ключ/значение в HashMap таким же образом, как мы делали с векторами, используя цикл for :

fn main()  use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); for (key, value) in &scores < println!(": "); > > 

Этот код будет печатать каждую пару в произвольном порядке:

Yellow: 50 Blue: 10 

Хеш-карты и владение

Для типов, которые реализуют типаж Copy , например i32 , значения копируются в HashMap. Для значений со владением, таких как String , значения будут перемещены в хеш-карту и она станет владельцем этих значений, как показано в листинге 8-22.

fn main()  use std::collections::HashMap; let field_name = String::from("Favorite color"); let field_value = String::from("Blue"); let mut map = HashMap::new(); map.insert(field_name, field_value); // field_name and field_value are invalid at this point, try using them and // see what compiler error you get! > 

Листинг 8-22: Показывает, что ключи и значения находятся во владении HashMap, как только они были вставлены

Мы не можем использовать переменные field_name и field_value после того, как их значения были перемещены в HashMap вызовом метода insert .

Если мы вставим в HashMap ссылки на значения, то они не будут перемещены в HashMap. Значения, на которые указывают ссылки, должны быть действительными хотя бы до тех пор, пока хеш-карта действительна. Мы поговорим подробнее об этих вопросах в разделе "Валидация ссылок при помощи времён жизни" главы 10.

Обновление данных в HashMap

Хотя количество ключей и значений может увеличиваться в HashMap, каждый ключ может иметь только одно значение, связанное с ним в один момент времени (обратное утверждение неверно: команды "Blue" и "Yellow" могут хранить в хеш-карте scores одинаковое количество очков, например 10).

Когда вы хотите изменить данные в хеш-карте, необходимо решить, как обрабатывать случай, когда ключ уже имеет назначенное значение. Можно заменить старое значение новым, полностью игнорируя старое. Можно сохранить старое значение и игнорировать новое, или добавлять новое значение, если только ключ ещё не имел значения. Или можно было бы объединить старое значение и новое значение. Давайте посмотрим, как сделать каждый из вариантов!

Перезапись старых значений

Если мы вставим ключ и значение в HashMap, а затем вставим тот же ключ с новым значением, то старое значение связанное с этим ключом, будет заменено на новое. Даже несмотря на то, что код в листинге 8-23 вызывает insert дважды, хеш-карта будет содержать только одну пару ключ/значение, потому что мы вставляем значения для одного и того же ключа - ключа команды "Blue".

fn main()  use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Blue"), 25); println!("", scores); > 

Листинг 8-23: Замена значения, хранимого в конкретном ключе

Код напечатает . Начальное значение 10 было перезаписано.

Вставка значения только в том случае, когда ключ не имеет значения

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

Хеш-карты имеют для этого специальный API, называемый entry , который принимает ключ для проверки в качестве входного параметра. Возвращаемое значение метода entry - это перечисление Entry , с двумя вариантами: первый представляет значение, которое может существовать, а второй говорит о том, что значение отсутствует. Допустим, мы хотим проверить, имеется ли ключ и связанное с ним значение для команды "Yellow". Если хеш-карта не имеет значения для такого ключа, то мы хотим вставить значение 50. То же самое мы хотим проделать и для команды "Blue". Используем API entry в коде листинга 8-24.

fn main()  use std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.entry(String::from("Yellow")).or_insert(50); scores.entry(String::from("Blue")).or_insert(50); println!("", scores); > 

Листинг 8-24: Использование метода entry для вставки значения только в том случае, когда ключ не имеет значения

Метод or_insert определён в Entry так, чтобы возвращать изменяемую ссылку на соответствующее значение ключа внутри варианта перечисления Entry , когда этот ключ существует, а если его нет, то вставлять параметр в качестве нового значения этого ключа и возвращать изменяемую ссылку на новое значение. Эта техника намного чище, чем самостоятельное написание логики и, кроме того, она более безопасна и согласуется с правилами заимствования.

При выполнении кода листинга 8-24 будет напечатано . Первый вызов метода entry вставит ключ для команды "Yellow" со значением 50, потому что для жёлтой команды ещё не имеется значения в HashMap. Второй вызов entry не изменит хеш-карту, потому что для ключа команды "Blue" уже имеется значение 10.

Создание нового значения на основе старого значения

Другим распространённым вариантом использования хеш-карт является поиск значения по ключу, а затем обновление этого значения на основе старого значения. Например, в листинге 8-25 показан код, который подсчитывает, сколько раз определённое слово встречается в некотором тексте. Мы используем HashMap со словами в качестве ключей и увеличиваем соответствующее слову значение, чтобы отслеживать, сколько раз мы встретили это слово. Если мы впервые встретили слово, то сначала вставляем значение 0.

fn main()  use std::collections::HashMap; let text = "hello world wonderful world"; let mut map = HashMap::new(); for word in text.split_whitespace() < let count = map.entry(word).or_insert(0); *count += 1; >println!("", map); > 

Листинг 8-25: Подсчёт количества вхождений слов с использованием хеш-карты, которая хранит слова и счётчики

Этот код напечатает . Если вы увидите, что пары ключ/значение печатаются в другом порядке, то вспомните, что мы писали в секции "Доступ к данным в HashMap" , что итерация по хеш-карте происходит в произвольном порядке.

Метод split_whitespace возвращает итератор по срезам строки, разделённых пробелам, для строки text . Метод or_insert возвращает изменяемую ссылку ( &mut V ) на значение ключа. Мы сохраняем изменяемую ссылку в переменной count , для этого, чтобы присвоить переменной значение, необходимо произвести разыменование с помощью звёздочки (*). Изменяемая ссылка удаляется сразу же после выхода из области видимости цикла for , поэтому все эти изменения безопасны и согласуются с правилами заимствования.

Функция хеширования

По умолчанию HashMap использует функцию хеширования SipHash, которая может противостоять атакам класса отказ в обслуживании, Denial of Service (DoS) с использованием хеш-таблиц siphash . Это не самый быстрый из возможных алгоритмов хеширования, в данном случае производительность идёт на компромисс с обеспечением лучшей безопасности. Если после профилирования вашего кода окажется, что хеш-функция, используемая по умолчанию, очень медленная, вы можете заменить её используя другой hasher. Hasher - это тип, реализующий трейт BuildHasher . Подробнее о типажах мы поговорим в Главе 10. Вам совсем не обязательно реализовывать свою собственную функцию хеширования; crates.io имеет достаточное количество библиотек, предоставляющих разные реализации hasher с множеством общих алгоритмов хеширования.

Итоги

Векторы, строки и хеш-карты предоставят большое количество функционала для программ, когда необходимо сохранять, получать доступ и модифицировать данные. Теперь вы готовы решить следующие учебные задания:

  • Есть список целых чисел. Создайте функцию, используйте вектор и верните из списка: среднее значение; медиану (значение элемента из середины списка после его сортировки); моду списка (mode of list, то значение которое встречается в списке наибольшее количество раз; HashMap будет полезна в данном случае).
  • Преобразуйте строку в кодировку "поросячьей латыни" (Pig Latin). Первая согласная каждого слова перемещается в конец и к ней добавляется окончание "ay", так "first" станет "irst-fay". Слову, начинающемуся на гласную, в конец добавляется "hay" ("apple" становится "apple-hay"). Помните о деталях работы с кодировкой UTF-8!
  • Используя хеш-карту и векторы, создайте текстовый интерфейс позволяющий пользователю добавлять имена сотрудников к названию отдела компании. Например, "Add Sally to Engineering" или "Add Amir to Sales". Затем позвольте пользователю получить список всех людей из отдела или всех людей в компании, отсортированных по отделам в алфавитном порядке.

Документация API стандартной библиотеки описывает методы у векторов, строк и HashMap. Рекомендуем воспользоваться ей при решении упражнений.

Потихоньку мы переходим к более сложным программам, в которых операции могут потерпеть неудачу. Наступило идеальное время для обсуждения обработки ошибок.

Хэширование в Java на примере HashMap и HashSet

Рассмотрели основы хэширования в Java и объясним цели использования HashMap и HashSet с примерами синтаксиса.

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

В этом блог-посте мы исследуем хэширование в контексте языка программирования Java, с акцентом на двух важных классах: HashMap и HashSet.

Мы рассмотрим основы хэширования, объясним цель и использование HashMap и HashSet, предоставим примеры синтаксиса на Java, покажем практические примеры использования и обсудим шаблоны решения проблем. Давайте начнем!

Что такое хэширование

Хэширование – это техника, используемая для отображения данных на фиксированное значение, известное как хэш-код или хэш. Она берет входные данные, выполняет некоторые вычисления над ними и генерирует уникальный хэш-код. Полученный хэш-код используется в качестве индекса или ключа для хранения или извлечения данных из структуры данных.

Что такое HashMap

HashMap – это класс в коллекциях Java, который реализует интерфейс Map. Он предоставляет способ хранения пар ключ-значение, где каждый ключ является уникальным. Ключи хэшируются для генерации хэш-кодов, которые затем используются для индексации и хранения соответствующих значений. HashMap обеспечивает эффективное извлечение и изменение данных.

Java-синтаксис для HashMap

Для создания HashMap в Java вам необходимо импортировать класс java.util.HashMap. Вот синтаксис создания HashMap:

import java.util.HashMap; HashMap map = new HashMap<>(); 

KeyType представляет тип данных ключей, а ValueType представляет тип данных значений.

Главные методы в HashMap

  • put(key, value): Вставляет пару ключ-значение в HashMap.
  • get(key): Извлекает значение, связанное с указанным ключом.
  • containsKey(key): Проверяет, содержит ли HashMap указанный ключ.
  • containsValue(value): Проверяет, содержит ли HashMap указанное значение.
  • remove(key): Удаляет пару ключ-значение, связанную с указанным ключом.
  • size(): Возвращает количество пар ключ-значение в HashMap.

Пример Java-кода для HashMap

Предположим, у нас есть пример, где мы храним возраст людей, используя их имена в качестве ключей в HashMap:

import java.util.HashMap; HashMap ageMap = new HashMap<>(); ageMap.put("Alice", 28); ageMap.put("Bob", 35); ageMap.put("Charlie", 42); System.out.println(ageMap.get("Alice")); // Output: 28 

В этом примере мы создаем HashMap с типом ключа String и типом значения Integer. Затем мы добавляем несколько пар ключ-значение и извлекаем возраст Алисы, используя ее имя в качестве ключа.

Что такое HashSet

HashSet – это еще один класс в коллекциях Java, который реализует интерфейс Set. Он представляет собой набор уникальных элементов, где порядок не имеет значения. HashSet использует хэширование внутренне для эффективного хранения и извлечения элементов.

Java-синтаксис для HashSet

Для создания HashSet в Java вам необходимо импортировать класс java.util.HashSet. Вот синтаксис:

import java.util.HashSet; HashSet set = new HashSet<>(); 

ElementType представляет тип данных элементов в наборе.

Главные методы в HashSet

  • add(element): Добавляет элемент в HashSet.
  • contains(element): Проверяет, содержит ли HashSet указанный элемент.
  • remove(element): Удаляет элемент из HashSet.
  • size(): Возвращает количество элементов в HashSet.

Пример Java-кода для HashSet

Предположим, у нас есть пример, где мы храним список уникальных имен, используя HashSet:

import java.util.HashSet; HashSet nameSet = new HashSet<>(); nameSet.add("Alice"); nameSet.add("Bob"); nameSet.add("Charlie"); System.out.println(nameSet.contains("Alice")); // Output: true 

В данном примере мы создаем HashSet с типом элемента String. Мы добавляем три уникальных имени и проверяем, существует ли “Alice” в наборе с помощью метода contains().

В каких случаях использовать HashMap и HashSet

  1. Индексирование данных: HashMap обычно используется для эффективного индексирования и извлечения данных на основе уникальных ключей. Например, его можно использовать для хранения профилей пользователей, где ключами будут их имена пользователя.
  2. Удаление дубликатов: HashSet полезен для удаления повторяющихся элементов из коллекции. Он может использоваться для фильтрации уникальных значений из списка или для проверки наличия дубликатов.
  3. Кэширование: HashMap может быть использован в качестве механизма кэширования, где можно сохранять и извлекать быстро результаты дорогостоящих вычислений или запросов к базе данных с использованием уникальных ключей.

Паттерны решения задач с HashMap и HashSet

  1. Подсчет частоты: HashMap может быть использован для подсчета частоты элементов в списке или строке. Он полезен при решении задач, связанных с поиском дубликатов или анализом встречаемости символов/слов.
  2. Множественные операции: HashSet предоставляет эффективные операции над множествами, такие как объединение, пересечение и разность. Эти операции полезны при решении задач, связанных с поиском общих элементов или уникальных значений.

Заключение

Хеширование – мощная техника, которая позволяет эффективно хранить и извлекать данные в Java. HashMap и HashSet – два важных класса, которые используют хеширование для предоставления отображения ключ-значение и хранения уникальных элементов соответственно.

Понимая концепции, синтаксис, практические примеры использования, важные методы и паттерны решения задач с использованием HashMap и HashSet, у вас будет прочный фундамент для эффективного использования этих классов в ваших Java-проектах.

Следите за новыми постами по любимым темам

Подпишитесь на интересующие вас теги, чтобы следить за новыми постами и быть в курсе событий.

Что такое hashmap

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

No Name Уровень 32
11 июня 2023
+ статья в копилку
Ислам Уровень 32
31 мая 2023
10 апреля 2023

“Анна Ивановна Решетникова, 4211 717171” И как они собирались хранить такой номер паспорта в типе Integer? Тем самым показав, что номер паспорта хранить в базе данных как число - это не лучшая идея. Так как номера паспорта могут содержать дефисы, пробелы, буквы и т.д. Поправьте меня, если я не прав. Иначе у меня вопросы к господину Милану.

Sm1le84 Уровень 10 Student
25 февраля 2023

Скажите, почему хронология вывода на экран поменялась?

ChupaFx Уровень 32
24 февраля 2023

Получение списка всех ключей и значений Еще одна удобная особенность HashMap — можно по-отдельности получить список всех ключей и всех значений. Для этого используются методы keySet() и values() Для чего в примере создаются Set и ArrayList? Если в sout можно прямо вызвать методы keySet() и values()?

Denis Odesskiy Уровень 28
12 февраля 2023

Возможно ли в HashMap переопределить метод toString() и если да, то каким образом? P/S: Спросил нынче модный ChatGPT, так он какую-то чушь городит: то пишет можно и даёт нерабочие коды, каждый раз разные, то пишет что нельзя потому что HashMap происходит от абстрактного класса. Хотя я уже понял что верить ему нельзя во всем, на вопрос можно ли реализовать в Java множественное наследование (не через интерфейсы) он бодро рапортовал, что конечно можно и вывалил код типа public сlass A extends B, C, который естественно не работает. Извините за возможный оффтоп. Так что роботы пока не завоюют мир, поэтому, вопрос по toString() все еще актуален. )

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *