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

Java lang classcastexception что это

  • автор:

ошибка java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer

Задача простая. Чтобы один из элементов карточки заполнялся рандомным цветом и при клике на эту карточку открывалась активити, тулбар которой заполнялся бы тем же цветом. Но вылезает ошибка java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer Один тип не может быть приведен к другому. Меняла приведение типов, ничего не помогает. Ошибка именно при передачи цвета в тулбар, т.к. без этого код работает. Помогите разобраться. В onCreateViewHolder устанавливаю элементу рандомный цвет

 int[] androidColors = view.getResources().getIntArray(R.array.androidColors); int randomAndroidColor = androidColors[new Random().nextInt(androidColors.length)]; if (frameLayout != null)

В классе активити, показывающей подробное описание:

public static final String EXTRA_POEM_ID = "poem_id"; public static final String EXTRA_COLOR = "random_android_color"; private long poemId; private int randomAndroidColor; poemId = getIntent().getLongExtra(EXTRA_POEM_ID, -1); randomAndroidColor = getIntent().getIntExtra(EXTRA_COLOR, 0); toolbar.setBackgroundColor(randomAndroidColor); 

В адаптере создан интерфейс:

 itemView.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < long poemId = (Long) v.getTag(); int randomAndroidColor = (int) v.getTag(); onPoemClickListener.onPoemClick(poemId, randomAndroidColor); >>); > > public interface OnPoemClickListener

и код фрагмента, где располагается список с карточками

 private final PoemsAdapter.OnPoemClickListener onPoemClickListener = new PoemsAdapter.OnPoemClickListener() < @Override public void onPoemClick(long poemId, int randomAndroidColor) < Intent intent = new Intent(getActivity(), ReadActivity.class); intent.putExtra(ReadActivity.EXTRA_POEM_ID, poemId); intent.putExtra(ReadActivity.EXTRA_COLOR, randomAndroidColor); startActivity(intent); >>; 

Java lang classcastexception что это

Брошенный, чтобы указать, что код попытался бросить объект к подклассу, которого это не экземпляр. Например, следующий код генерирует a ClassCastException :

Object x = new Integer(0); System.out.println((String)x);

Сводка конструктора

Конструкции a ClassCastException без сообщения детали.

Конструкции a ClassCastException с указанным сообщением детали.

Сводка метода

Методы java.lang унаследованный от класса. Throwable

Методы java.lang унаследованный от класса. Объект

Деталь конструктора

ClassCastException
public ClassCastException()

Конструкции a ClassCastException без сообщения детали.

ClassCastException

Конструкции a ClassCastException с указанным сообщением детали.

Платформа Java™
Стандарт Эд. 7

Представьте ошибку или функцию
Для дальнейшей ссылки API и документации разработчика, см. Java Документация SE . Та документация содержит более подробные, предназначенные разработчиком описания, с концептуальными краткими обзорами, определениями сроков, обходных решений, и рабочих примеров кода.
Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.

Объяснение ClassCastException в Java

ClassCastException — это непроверенное исключение , которое сигнализирует о том, что код попытался привести ссылку к типу, подтипом которого он не является .

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

2. Явный кастинг​

Для наших следующих экспериментов рассмотрим следующие классы:

 public interface Animal    String getName();   > 
 public class Mammal implements Animal    @Override   public String getName()    return "Mammal";   >   > 
 public class Amphibian implements Animal    @Override   public String getName()    return "Amphibian";   >   > 
 public class Frog extends Amphibian    @Override   public String getName()    return super.getName() + ": Frog";   >   > 

2.1. Классы кастинга​

На сегодняшний день наиболее распространенным сценарием возникновения ClassCastException является явное приведение к несовместимому типу.

Например, давайте попробуем привести лягушку к млекопитающему :

 Frog frog = new Frog();   Mammal mammal = (Mammal) frog; 

Мы могли бы ожидать здесь ClassCastException , но на самом деле мы получаем ошибку компиляции: «несовместимые типы: лягушка не может быть преобразована в млекопитающее». Однако ситуация меняется, когда мы используем общий супертип:

 Animal animal = new Frog();   Mammal mammal = (Mammal) animal; 

Теперь мы получаем ClassCastException из второй строки:

 Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class Mammal (Frog and Mammal are in unnamed module of loader 'app')  at Main.main(Main.java:9) 

Проверенное нисходящее приведение к Mammal несовместимо со ссылкой Frog, потому что Frog не является подтипом Mammal . В этом случае компилятор нам помочь не сможет, так как переменная Animal может содержать ссылку совместимого типа.

Интересно отметить, что ошибка компиляции возникает только тогда, когда мы пытаемся выполнить приведение к однозначно несовместимому классу. То же самое не верно для интерфейсов, потому что Java поддерживает множественное наследование интерфейсов, но только одиночное наследование для классов. Таким образом, компилятор не может определить, реализует ли ссылочный тип конкретный интерфейс или нет. Приведем пример:

 Animal animal = new Frog();   Serializable serial = (Serializable) animal; 

Мы получаем ClassCastException во второй строке вместо ошибки компиляции:

 Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class java.io.Serializable (Frog is in unnamed module of loader 'app'; java.io.Serializable is in module java.base of loader 'bootstrap')  at Main.main(Main.java:11) 

2.2. Приведение массивов​

Мы видели, как классы обрабатывают приведение типов, теперь давайте посмотрим на массивы. Приведение массивов работает так же, как приведение классов. Однако нас может запутать автоупаковка и продвижение шрифта или их отсутствие.

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

 Object primitives = new int[1];   Integer[] integers = (Integer[]) primitives; 

Вторая строка генерирует исключение ClassCastException , так как автоупаковка не работает для массивов.

Как насчет продвижения типа? Давайте попробуем следующее:

 Object primitives = new int[1];   long[] longs = (long[]) primitives; 

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

2.3. Безопасный кастинг​

В случае явного приведения настоятельно рекомендуется проверить совместимость типов перед попыткой приведения с использованием instanceof .

Давайте посмотрим на пример безопасного приведения:

 Mammal mammal;   if (animal instanceof Mammal)    mammal = (Mammal) animal;   > else    // handle exceptional case   > 

3. Загрязнение кучи​

В соответствии со спецификацией Java : « Загрязнение кучи может произойти только в том случае, если программа выполнила какую-либо операцию с необработанным типом, которая привела бы к непроверенному предупреждению во время компиляции».

Для нашего эксперимента рассмотрим следующий универсальный класс:

 public static class Box    private T content;    public T getContent()    return content;   >    public void setContent(T content)    this.content = content;   >   > 

Теперь попробуем загрязнить кучу следующим образом:

 BoxLong> originalBox = new Box>();   Box raw = originalBox;  raw.setContent(2.5);   BoxLong> bound = (BoxLong>) raw;   Long content = bound.getContent(); 

Последняя строка вызовет исключение ClassCastException , поскольку она не может преобразовать двойную ссылку в Long .

4. Общие типы​

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

Рассмотрим следующий общий метод:

 public static T> T convertInstanceOfObject(Object o)    try    return (T) o;   > catch (ClassCastException e)    return null;   >   > 

А теперь назовем это:

 String shouldBeNull = convertInstanceOfObject(123); 

На первый взгляд, мы можем разумно ожидать, что из блока catch будет возвращена нулевая ссылка. Однако во время выполнения из-за стирания типа параметр приводится к Object вместо String . Таким образом, перед компилятором стоит задача присвоить Integer String , что вызовет исключение ClassCastException.

5. Вывод​

В этой статье мы рассмотрели ряд распространенных сценариев неуместного кастинга.

Неявное или явное приведение ссылок Java к другому типу может привести к ClassCastException , если только целевой тип не является тем же или потомком фактического типа .

Код, использованный в этой статье, можно найти на GitHub .

  • 1. Обзор
  • 2. Явный кастинг
    • 2.1. Классы кастинга
    • 2.2. Приведение массивов
    • 2.3. Безопасный кастинг

    3 трюка для устранения странных ошибок с дженериками

    Деловое фото создано yanalya — www.freepik.com

    Большинство разработчиков Java используют дженерики без глубоких знаний. А вы должны знать ответы на эти вопросы. Если вы будете знать их, вы устраните многие проблемы, связанные с generics .

    Давайте ответим на эти вопросы.

    1. Вы можете использовать extends с интерфейсами

    Согласно этим документам, вы можете использовать interfaceType после ключевого слова extends . Вы можете соединить их в цепочку, чтобы сформировать типы пересечения. Это может привести к странным ошибкам во время выполнения.

    Давайте рассмотрим следующий вопрос на Stack Overflow.

    Код в вопросе следующий:

     X getCharSequence() < return (X) "hello"; > X getString()

    Если мы запустим его в jShell 11, то получим следующий результат:

    jshell> X getCharSequence() < . >return (X) "hello"; . > > . > . > X getString() < . >return (X) "hello"; . > > | Warning: | unchecked cast | required: X | found: java.lang.String | return (X) "hello"; | ^-----^ | created method getCharSequence() | Warning: | unchecked cast | required: X | found: java.lang.String | return (X) "hello"; | ^-----^ | created method getString() jshell> Integer x = getCharSequence(); . > | Exception java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap') | at (#3:1) jshell> Integer y = getString(); . > | Error: | incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String | Integer y = getString();

    В обоих примерах мы получаем предупреждение о непроверенном приведении. Это потому, что в обоих примерах мы возвращаем String , а не X . Тем не менее, оба метода создаются.

    Когда мы загружаем getCharSequence , мы получаем не ошибку времени компиляции, а ошибку времени выполнения. Для getString мы получаем ошибку времени компиляции.

    Почему так происходит?

    Для первого метода Java определяет тип пересечения. В данном случае это Integer & CharSequence а Integer может быть подклассом CharSequence . Вот почему с точки зрения компиляции это корректное присваивание, несмотря на то, что Integer является final class.

    Ошибка во время выполнения возникает, поскольку мы возвращаем значение String , не соответствующее типу Integer & CharSequence . Поскольку проверки во время выполнения нет, мы получаем исключение ClassCastException .

    Почему во втором примере возникает ошибка времени компиляции?

    String — это final класс, и вы не можете расширить его как String . Он не относится к типу CharSequence , который является интерфейсом. Ему невозможно иметь тип пересечения Integer & String , и это известно во время компиляции.

    2. Вы можете создавать типобезопасные generic массивы

    Один из способов создания generic массивов заключается в следующем:

    public T[] array(T. values)

    Но даже в этом случае выдается следующее предупреждение:

    jshell> public T[] array(T. values) < . >return values; . > > | Warning: | Possible heap pollution from parameterized vararg type T | public T[] array(T. values) < | ^---------^ | created method array(T. )

    Так что же означает загрязнение кучи (heap pollution)?

    Переменная содержит ссылку на неправильный тип. Или, другими словами, тип переменной не является нужным типом.

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

    Вы можете подавить эти предупреждения. И это используется в одном методе, который мы все используем: Collections#emptyList()

    Так почему же этот сценарий хорош?

    Вы можете быть уверены, что даже при стирании типов (type erasure) будет создан пустой список нужного типа. Вы можете быть спокойны, потому что это пустой список, поэтому подойдет любой тип.

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

    А вот наша собственная реализация.

    jshell> class Generic  < . >. > private E[] array; . > . > GenericSet(IntFunction generator) < . >this.array = generator.apply(0); . > > . > . > public static void main(String[] args) < . >Generic ofString = . > new Generic<>(String[]::new); . > Generic ofDouble = . > new Generic<>(Double[]::new); . > > . > >

    3. Producer Extends, Consumer Super

    Я полагаю, вы встречали и extends и super в Java коде с generic.

    Так почему вы должны использовать extends ? Каковы ограничения extends ? И какова цель super ?

    • Producer Extends — если вам нужен List , чтобы выдавать значения T (вы хотите читать T из списка), вам нужно объявить его с помощью ? extends T , например, List . Но вы не можете добавить значение в этот список.
    • Consumer Super— если вам нужен List для получения значений типа T (вы хотите записывать значения типа T в список), вам нужно объявить его с помощью ? super T , например, List . Но нет никаких гарантий, какой тип объекта вы можете прочитать из этого списка.

    Вы не можете добавить в список производителей, и вы не можете прочитать из списка потребителей.

    jshell> List foo3 = List.of(1.23); foo3 ==> [1.23] jshell> foo3.get(0) $27 ==> 1.23 jshell> foo3.add(1.34) | Error: | incompatible types: double cannot be converted to capture#10 of ? extends java.lang.Number | foo3.add(1.34) | ^--^
    jshell> List foo3 = new ArrayList(); foo3 ==> [] jshell> foo3.add(1) $32 ==> true jshell> foo3 foo3 ==> [1] jshell> foo3.get(0) $34 ==> 1 jshell> Number r = foo3.get(0) | Error: | incompatible types: capture#11 of ? super java.lang.Number cannot be converted to java.lang.Number | Number r = foo3.get(0); | ^---------^

    Почему это происходит?

    Нет гарантии с обеих сторон, так как происходит стирание типов.

    Когда вы используете extends , у вас есть гарантия того, что вы можете читать. Это тип после wildcard знака extends или его подклассов. И у вас нет гарантии того, что вы можете добавить, так как тип стирается во время выполнения.

    Когда вы используете super , у вас есть гарантия того, какой тип вы можете добавить. Это тип после wildcard super или его подклассов. И у вас нет гарантии того, что вы можете прочитать, так как тип стирается во время выполнения.

    Еще одно хорошее и простое объяснение (source):

    dst будет потреблять значения типа T, поэтому wildcard super гарантирует это. src будет производить значения, поэтому extends будет гарантировать это. Но даже в этом случае нет гарантии типа при добавлении в src или чтении из dst .

    Что, если вы заранее знаете типы и хотите использовать wildcard?

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

    Допустим, мы используем super (Consumer из PECS) для foo3 . С помощью явного приведения к List вы можете гарантировать какой тип вы читаете из foo3Unchecked . В данном случае мы гарантируем, что это Number что чтение Integer приведет к ошибке преобразования.

    Какие особенности дженериков вы знаете? Дайте мне знать в разделе комментариев.

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

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