← Назад к вопросам
Может ли поток в synchronized методе войти еще раз в этот же метод?
2.0 Middle🔥 141 комментариев
#Многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Примитив как ключ в Map
Краткий ответ: Нет, примитивы НЕ могут быть ключами в HashMap/TreeMap, но их обёрнутые версии (Integer, Double, Long) могут и часто используются.
Почему примитивы не могут быть ключами
Причина: HashMap и TreeMap требуют методов hashCode() и equals(), которые есть только у объектов. Примитивы не наследуют эти методы.
// ❌ Синтаксическая ошибка: примитивы не допускаются
Map<int, String> map1 = new HashMap<>(); // ❌ Ошибка компиляции
Map<double, String> map2 = new HashMap<>(); // ❌ Ошибка компиляции
Map<boolean, String> map3 = new HashMap<>(); // ❌ Ошибка компиляции
// ✓ Правильно: используем обёрнутые типы
Map<Integer, String> map1 = new HashMap<>(); // ✓ OK
Map<Double, String> map2 = new HashMap<>(); // ✓ OK
Map<Boolean, String> map3 = new HashMap<>(); // ✓ OK
Использование обёрнутых примитивов
public class WrapperTypesAsKeys {
public static void main(String[] args) {
// Integer как ключ
Map<Integer, String> intMap = new HashMap<>();
intMap.put(1, "One");
intMap.put(2, "Two");
intMap.put(3, "Three");
System.out.println(intMap); // {1=One, 2=Two, 3=Three}
// Double как ключ
Map<Double, String> doubleMap = new HashMap<>();
doubleMap.put(1.5, "One-point-five");
doubleMap.put(2.7, "Two-point-seven");
System.out.println(doubleMap);
// Boolean как ключ (максимум 2 элемента!)
Map<Boolean, String> boolMap = new HashMap<>();
boolMap.put(true, "Yes");
boolMap.put(false, "No");
System.out.println(boolMap);
}
}
Почему обёрнутые типы работают
// Integer имеет методы hashCode() и equals()
public class IntegerExample {
public static void main(String[] args) {
Integer a = 42;
Integer b = 42;
Integer c = new Integer(42);
System.out.println(a.equals(b)); // true
System.out.println(a.hashCode()); // 42
System.out.println(b.hashCode()); // 42
System.out.println(a.hashCode() == c.hashCode()); // true
// Поэтому они работают как ключи
Map<Integer, String> map = new HashMap<>();
map.put(a, "First");
map.put(b, "Second"); // Перезаписывает значение для того же ключа
System.out.println(map.get(c)); // "Second"
}
}
Autoboxing/Unboxing
public class AutoboxingExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
// ✓ Autoboxing: примитив автоматически оборачивается
map.put(1, "One"); // int → Integer
map.put(2, "Two");
// ✓ Unboxing: Integer автоматически разворачивается
Integer key = 1;
String value = map.get(key);
System.out.println(value); // "One"
}
}
Сравнение типов
public class TypeComparison {
public static void main(String[] args) {
// ❌ int: примитив
int primitive = 5;
System.out.println(primitive.hashCode()); // ❌ Ошибка: int не имеет методов
// ✓ Integer: объект (обёртка)
Integer wrapped = 5;
System.out.println(wrapped.hashCode()); // ✓ OK: 5
// Они эквивалентны в коллекциях
Map<Integer, String> map = new HashMap<>();
map.put(5, "Five");
System.out.println(map.get(wrapped)); // "Five"
System.out.println(map.get(5)); // "Five" (autoboxing)
}
}
Осторожность с Double/Float
public class DoubleKeyWarning {
public static void main(String[] args) {
Map<Double, String> map = new HashMap<>();
// ⚠️ Осторожность: floating-point ошибки
double d1 = 0.1 + 0.2; // 0.30000000000000004
double d2 = 0.3; // 0.3
map.put(d1, "Sum");
System.out.println(map.get(d2)); // null (не найдено!)
// Лучше использовать BigDecimal
Map<BigDecimal, String> bdMap = new HashMap<>();
bdMap.put(BigDecimal.valueOf(0.1).add(BigDecimal.valueOf(0.2)), "Sum");
bdMap.put(BigDecimal.valueOf(0.3), "Direct");
}
}
Практические примеры
public class PracticalExamples {
// ✓ Хорошо: Integer как ключ (стабильный hashCode)
public Map<Integer, User> getUsersById(List<User> users) {
return users.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
}
// ✓ Хорошо: String как ключ
public Map<String, Integer> getWordFrequency(List<String> words) {
return words.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.summingInt(w -> 1)
));
}
// ⚠️ Осторожность: Boolean (максимум 2 ключа)
public Map<Boolean, Integer> getCountByStatus(List<Data> data) {
return data.stream()
.collect(Collectors.groupingBy(
Data::isActive,
Collectors.summingInt(d -> 1)
));
}
// ❌ Избегай: Double из-за точности
// Используй BigDecimal вместо Double
public Map<BigDecimal, Price> getPrices() {
Map<BigDecimal, Price> map = new HashMap<>();
return map;
}
}
Сравнение примитивов и обёрток
| Тип | Примитив | Обёртка | Как ключ |
|---|---|---|---|
| целое число | int | Integer | ✓ Integer |
| вещество | double | Double | ⚠️ осторожно Double |
| логический | boolean | Boolean | ✓ Boolean (макс 2) |
| символ | char | Character | ✓ Character |
Вывод: Примитивы не могут быть ключами напрямую. Используй обёрнутые типы (Integer, Double, Boolean и т.д.). Осторожнее с Double/Float из-за точности вычислений.