Объяснение "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 {...}
- Вы можете привести любую из этих вещей к Object, потому что все классы Java наследуются от Object.
- Вы можете разыграть B или C на A, потому что они оба "вида" A
- Вы можете привести ссылку на объект A к B, только если реальный объект - B.
- Вы не можете бросить 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
:
- Будьте осторожны, пытаясь привести объект одного класса в другой. Убедитесь, что новый тип принадлежит одному из его родительских классов.
- Вы можете предотвратить 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.