public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
A atribuição Dog dog = (Dog) animal;
não gera um erro de compilação, mas em tempo de execução, gera a ClassCastException
. Por que o compilador não pode detectar esse erro?
java
casting
classcastexception
saravanan
fonte
fonte
Respostas:
Ao usar um elenco, você está basicamente dizendo ao compilador "confie em mim. Sou profissional, sei o que estou fazendo e sei que, embora você não possa garantir isso, estou lhe dizendo que isso
animal
variável é definitivamente vai ser um cachorro. "Como o animal não é realmente um cachorro (é um animal, você poderia fazer
Animal animal = new Dog();
e seria um cachorro), a VM lança uma exceção em tempo de execução porque você violou essa confiança (você disse ao compilador que tudo ficaria bem e é não!)O compilador é um pouco mais inteligente do que aceitar cegamente tudo, se você tentar converter objetos em hierarquias de herança diferentes (converter um Dog em uma String, por exemplo), o compilador o jogará de volta para você, porque sabe que isso nunca poderia funcionar.
Como você está basicamente impedindo que o compilador se queixe, toda vez que você lança, é importante verificar se você não causará um
ClassCastException
usandoinstanceof
uma instrução if (ou algo nesse sentido).fonte
Dog
se estende deAnimal
!Porque teoricamente
Animal animal
pode ser um cachorro:Geralmente, fazer downcasting não é uma boa ideia. Você deveria evitá-lo. Se você usá-lo, é melhor incluir uma verificação:
fonte
Para evitar esse tipo de ClassCastException, se você tiver:
Você pode definir um construtor em B que aceite um objeto A. Assim, podemos fazer o "cast", por exemplo:
fonte
Elaborando a resposta dada por Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Aqui você está dizendo ao compilador "Confie em mim. Eu sei que
d
realmente está se referindo a umDog
objeto", embora não seja. Lembre-se de que o compilador é forçado a confiar em nós quando fazemos um downcast .Portanto, quando a JVM no tempo de execução descobre que na
Dog d
verdade se refere aAnimal
umDog
objeto e não a um objeto, diz. Ei ... você mentiu para o compilador e jogou muita gorduraClassCastException
.Portanto, se você está
instanceof
fazendo downcast, deve usar o teste para evitar estragar.if (animal instanceof Dog) { Dog dog = (Dog) animal; }
Agora uma pergunta vem à nossa mente. Por que o compilador infernal está permitindo o downcast quando, eventualmente, ele vai lançar um
java.lang.ClassCastException
?A resposta é que tudo o que o compilador pode fazer é verificar se os dois tipos estão na mesma árvore de herança, portanto, dependendo do código que possa ter vindo antes do downcast, é possível que
animal
seja do tipodog
.Considere o seguinte trecho de código:
No entanto, se o compilador tiver certeza de que o elenco não funcionaria, a compilação falhará. IE Se você tentar converter objetos em diferentes hierarquias de herança
String s = (String)d; // ERROR : cannot cast for Dog to String
Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast
Ambos os upcast acima funcionarão bem, sem exceção, porque um cão é um animal, anithing um animal pode fazer, um cão pode fazer. Mas não é verdade vica-versa.
fonte
O código gera um erro de compilação porque seu tipo de instância é um Animal:
O downcasting não é permitido em Java por vários motivos. Veja aqui para detalhes.
fonte
Como explicado, não é possível. Se você deseja usar um método da subclasse, avalie a possibilidade de adicionar o método à superclasse (pode estar vazia) e chame as subclasses obtendo o comportamento desejado (subclasse) graças ao polimorfismo. Portanto, quando você chama d.method (), a chamada será bem-sucedida sem a transmissão, mas, caso o objeto não seja um cachorro, não haverá problema.
fonte
Para desenvolver a resposta de @Caumons:
Agora, dê uma olhada nesta solução.
Agora testamos a aplicação:
E aqui está o resultado :
Agora você pode facilmente adicionar novos campos à classe pai sem se preocupar com a quebra dos códigos de seus filhos;
fonte