Тип Object не может быть безопасно приведен к HashMap<Object, Object>

Я получаю эту ошибку и не понимаю, почему и как ее исправить. «Тип Object не может быть безопасно приведен к HashMap<Object, Object>» в «inputObject instanceof HashMap<Object, Object>»

private void readCache() {
        try {
            ObjectInputStream objectStream = new ObjectInputStream(new FileInputStream(cacheFile));
            
            Object inputObject = objectStream.readObject();
            
            objectStream.close();
            
            if (inputObject instanceof HashMap<Object, Object>) {
                cache = (HashMap<Object, Object>) inputObject;
            }else {
                throw new CacheException("wrong cache type");
            }
        } catch (ClassNotFoundException | IOException e) {
            throw new CacheException(e);
        }
        
    }

Я пытался прочитать HashMap<Object,Object> из файла. Я ожидал, что это сработает.

Из-за стирания типов (docs.oracle.com) мы не можем проверять универсальные типы во время приведения. --- Это ошибка или «просто» предупреждение о стиле кода из вашей IDE?

Turing85 01.04.2024 13:29

@Turing85 Turing85 Нет, это ошибка во время компиляции. Я отредактировал вопрос, чтобы было понятнее.

Kaspi 01.04.2024 13:59
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
145
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что дженерики — плод воображения компилятора: во время выполнения ни один экземпляр понятия не имеет, что такое дженерики. следовательно, instanceof Map — это нормально, а instanceof Map<Object, Object> — нет. Вы можете спросить объект: «Вы карта?» и оно может ответить. Вы не можете спросить его: «Вы Map<Object, Object>», потому что он не знает.

Javac позволит вам написать это, но это утверждение программиста, как только вы напишете приведение. Таким образом, это:

if (inputObject instanceof HashMap) {
  cache = (HashMap<Object, Object>) inputObject;
} else {
  throw new CacheException("wrong cache type");
}

Будет «работать», но выдаст предупреждение, потому что эта <Object, Object> часть является утверждением программиста. Вы говорите компилятору: поверьте мне. Я знаю, это. Потому что ни компилятор, ни среда выполнения не имеют возможности проверить, действительно ли это так. Можете сохранить Map<String, InputStream> и здесь все получится.

Единственное, что вы можете сделать, это Map<?, ?> вместо этого. Это нормально: ? в обобщенном значении означает «я не знаю», поэтому читайте map = (Map<?, ?>) someVal; как:

«Проверьте, что это выражение someVal указывает на объект, типом которого является Карта, которая сопоставляется с ключами типа «Не знаю» значениям типа «Не знаю»».

Объекты могут прекрасно ответить на этот вопрос. Он знает, является ли это Map или нет (поскольку объекты знают свой собственный тип без дженериков), и, хотя они не знают своих собственных дженериков, они могут тривиально ответить «да» на вопрос: «Вы сопоставляете «кто знает что» с «что?» ' - конечно, да.

Вы по-прежнему можете вызвать .get(anyObj) для Map<?, ?>, и он вернет выражение типа Object. Он может это сделать, поскольку все типы являются объектами, поэтому карта, значения которой имеют тип «Я не знаю», будет, по крайней мере, объектами.

Следовательно, вы можете сделать это:

Map<?, ?> cache = ...;

if (inputObject instanceof HashMap) {
  cache = (HashMap<?, ?>) inputObject;
} else {
  throw new CacheException("wrong cache type");
}

но вы, вероятно, не хотите. Проблема с Map of who knows what to some unknown type заключается в том, что, хотя вы можете нормально вызвать .get(), по нему невозможно выполнить вызов .put, кроме как с помощью литерала null, и только потому, что литерал null относится ко всем типам одновременно и является единственным выражением. во всей Java, имеющей это свойство.

Ведь учитывая, что это карта, тип ключа которой неизвестен, помещать в нее, скажем, строку может быть некорректно. В конце концов, что, если ваша переменная типа Map<?, ?> указывает на объект типа HashMap<Integer, Integer>? Тогда если вставить туда веревку, все сломается!

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

class MyCache extends HashMap<Object, Object> {}

и сериализуйте это. Теперь нет никаких проблем и никаких предупреждений. Или используйте существующие решения для кэширования (например, guava) или другие механизмы сериализации.

Я должен не согласиться. У @SuppressWarnings нет законного использования. Почему не что-то вроде cache = new HashMap<Object, Object>((Map<?, ?>) inputObject);?

VGR 01.04.2024 16:59

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

rzwitserloot 01.04.2024 20:40

Мне еще предстоит столкнуться с использованием @SuppressWarnings в коде приложения, которого нельзя было бы избежать без особых усилий.

VGR 01.04.2024 21:19

Другие вопросы по теме