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

Я прочитал несколько статей, написанных на "ClassCastException", но я не смог получить хорошее представление об этом. Есть хорошая статья или какое краткое объяснение?

11 ответов

Решение

Прямо из API-спецификаций для ClassCastException:

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

Так, например, когда кто-то пытается разыграть Integer к String, String не подкласс Integer так ClassCastException будет брошен.

Object i = Integer.valueOf(42);
String s = (String)i;            // ClassCastException thrown here.

Это действительно довольно просто: если вы пытаетесь типизировать объект класса A в объект класса B, а они несовместимы, вы получаете исключение приведения класса.

Давайте подумаем о коллекции классов.

class A {...}
class B extends A {...}
class C extends A {...}
  1. Вы можете привести любую из этих вещей к Object, потому что все классы Java наследуются от Object.
  2. Вы можете разыграть B или C на A, потому что они оба "вида" A
  3. Вы можете привести ссылку на объект A к B, только если реальный объект - B.
  4. Вы не можете бросить B на C, даже если они оба.

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

Рассмотрим эту иерархию:

Объект -> Животное -> Собака

У вас может быть метод с именем:

 public void manipulate(Object o) {
     Dog d = (Dog) o;
 }

Если вызывается с этим кодом:

 Animal a = new Animal();
 manipulate(a);

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

В более поздних версиях Java вы получите предупреждение компилятора, если не сделаете:

 Dog d;
 if(o instanceof Dog) {
     d = (Dog) o;
 } else {
     //what you need to do if not
 }

Рассмотрим пример,

class Animal {
    public void eat(String str) {
        System.out.println("Eating for grass");
    }
}

class Goat extends Animal {
    public void eat(String str) {
        System.out.println("blank");
    }
}

class Another extends Goat{
  public void eat(String str) {
        System.out.println("another");
  }
}

public class InheritanceSample {
    public static void main(String[] args) {
        Animal a = new Animal();
        Another t5 = (Another) new Goat();
    }
}

В Another t5 = (Another) new Goat(): вы получите ClassCastException потому что вы не можете создать экземпляр Another класс с использованием Goat,

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

Как бороться с ClassCastException:

  1. Будьте осторожны, пытаясь привести объект одного класса в другой. Убедитесь, что новый тип принадлежит одному из его родительских классов.
  2. Вы можете предотвратить ClassCastException, используя Generics, потому что Generics предоставляют проверки времени компиляции и могут использоваться для разработки безопасных типов приложений.

Источник записки и отдыха

Вы понимаете концепцию кастинга? Кастинг - это процесс преобразования типов, который в Java очень распространен, потому что это статически типизированный язык. Некоторые примеры:

Приведите строку "1" к int -> без проблем

Приведение строки "abc" к int -> вызывает исключение ClassCastException

Или подумайте о диаграмме классов с Animal.class, Dog.class и Cat.class

Animal a = new Dog();
Dog d = (Dog) a; // No problem, the type animal can be casted to a dog, because its a dog.
Cat c = (Dog) a; // Raises class cast exception; you can't cast a dog to a cat.

Исключение приведения класса выдается Java при попытке приведения объекта одного типа данных к другому.

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

Например, вы можете привести String как Object, и, аналогично, Object, содержащий значения String, может быть приведен к String.

пример

Предположим, у нас есть HashMap, который содержит несколько объектов ArrayList.

Если мы напишем код так:

String obj = (String) hmp.get(key);

это вызовет исключение приведения класса, потому что значение, возвращаемое методом get хэш-карты, будет списком Array, но мы пытаемся привести его к String. Это вызвало бы исключение.

Вы пытаетесь рассматривать объект как экземпляр класса, которым он не является. Это примерно аналогично попытке нажать на демпферную педаль на гитаре (у пианино есть демпфирующие педали, у гитар нет).

Очень хороший пример, который я могу дать вам для classcastException в Java - это использование "Collection"

List list = new ArrayList();
list.add("Java");
list.add(new Integer(5));

for(Object obj:list) {
    String str = (String)obj;
}

Этот код выше даст вам ClassCastException во время выполнения. Поскольку вы пытаетесь привести Integer к String, это вызовет исключение.

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

Но если бы A был экземпляром B, это было бы возможно, потому что A - это ссылка на полный экземпляр B, поэтому отображение будет однозначным.

Исключение не является подклассом RuntimeException -> ClassCastException

    final Object  exception = new Exception();
    final Exception data = (RuntimeException)exception ;
    System.out.println(data);

Если вы хотите отсортировать объекты, но если класс не реализует Comparable или Comparator, вы получите ClassCastException. Например

class Animal{
   int age;
   String type;

   public Animal(int age, String type){
      this.age = age;
      this.type = type;
   }
}
public class MainCls{
   public static void main(String[] args){
       Animal[] arr = {new Animal(2, "Her"), new Animal(3,"Car")};
       Arrays.sort(arr);
   }
}

Выше основного метода будет выброшено исключение приведения класса ниже

Исключение в потоке "main" java.lang.ClassCastException: com.default.Animal не может быть приведено к java.lang.Comparable

Java ClassCastException - это исключение, которое может возникнуть при попытке неправильно преобразовать класс из одного типа в другой.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ClassCastExceptionExample {

  public ClassCastExceptionExample() {

    List list = new ArrayList();
    list.add("one");
    list.add("two");
    Iterator it = list.iterator();
    while (it.hasNext()) {
        // intentionally throw a ClassCastException by trying to cast a String to an
        // Integer (technically this is casting an Object to an Integer, where the Object 
        // is really a reference to a String:
        Integer i = (Integer)it.next();
    }
  }
 public static void main(String[] args) {
  new ClassCastExceptionExample();
 }
}

Если вы попытаетесь запустить эту Java-программу, вы увидите, что она выдаст следующую исключительную ситуацию ClassCastException:

Exception in thread "main" java.lang.ClassCastException: java.lang.String
at ClassCastExceptionExample  (ClassCastExceptionExample.java:15)
at ClassCastExceptionExample.main  (ClassCastExceptionExample.java:19)

Причина, по которой здесь выдается исключение, заключается в том, что когда я создаю свой объект списка, объект, который я сохраняю в списке, является строкой "один", но потом, когда я пытаюсь вывести этот объект, я намеренно совершаю ошибку, пытаясь бросить его в целое число. Поскольку String не может быть напрямую приведена к Integer - Integer не является типом String - выдается исключение ClassCastException.

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