O trecho de código a seguir resultará em um tempo de execução:
class Vehicle {
public void printSound() {
System.out.print("vehicle");
}
}
class Car extends Vehicle {
public void printSound() {
System.out.print("car");
}
}
class Bike extends Vehicle {
public void printSound() {
System.out.print("bike");
}
}
public class Test {
public static void main(String[] args) {
Vehicle v = new Car();
Bike b = (Bike) v;
v.printSound();
b.printSound();
}
}
Minha pergunta é: por que isso resulta em um erro de tempo de execução, mas não em um erro de compilação? O compilador não deve saber que "v" já é um "carro" e não pode ser lançado em uma "bicicleta"?
Respostas:
9 para resposta № 1Em teoria, seria possível para um compilador dizer a si mesmo: "v
é variável local, que é designada para ser um Car
. Em nenhum momento antes da tentativa de conversão para Bike
muda seu valor, e não há como Car
para ser lançado com sucesso para Bike
. Portanto, isso é um erro ".
No entanto, eu não conheço nenhum compilador Java que façaessa análise para você. Realmente só vale a pena no mais simples dos casos. Em vez disso, o comportamento é que o compilador vê o elenco e raciocina que é possível lançar um Vehicle
para um Bike
e assim é permitido.
Em geral, isso é o que um elenco significa: Ele diz ao compilador que mesmo que esta atribuição possa falhar, você tem certeza de que ela não irá. Em troca de permitir que o código compile, você assume o risco de uma exceção de tempo de execução.
4 para resposta № 2
Casting da superclasse pode funcionar, por isso é permitido (durante a compilação). Casting de uma classe totalmente diferente não é permitido, por exemplo:
Integer a = 1;
String b = (String)a; // compile error
String b = (String)(Object)a; // runtime error
3 para resposta № 3
Para
R r = /* some code to initialize "r" */
T t = (T) r;
o Especificação da linguagem Java diz:
Se R for uma classe comum (não uma classe de array):
- Se T é um tipo de classe, então R deve ser a mesma classe que T ou uma subclasse de T, ou uma exceção de tempo de execução é lançada.
- Se T é um tipo de interface, então R deve implementar a interface T ou uma exceção de tempo de execução é lançada.
- Se T for um tipo de matriz, será lançada uma exceção de tempo de execução.
1 para resposta № 4
Tipo de conversão de objeto ocorre em tempo de execução para que o compilador não o reconheça
0 para a resposta № 5
Não. v
é um Vehicle
e pode ser possível lançá-lo para Bike
. Não é tarefa do compilador descobrir os tipos reais de tempo de execução de cada objeto (especialmente porque às vezes isso é impossível).
0 para a resposta № 6
A semântica do Java diz que isso deve resultarem um erro de tempo de execução. Neste caso, é possível olhar para o código e ver que ele definitivamente lançará um erro em tempo de execução, mas como o compilador sabe que um ClassCastException
não é o que você queria?
Editores como IntelliJ e Eclipse podem (e fazem) notar esses tipos de erros e avisá-los sobre eles, mas as regras do Java dizem que este é um código legítimo que deve ser compilado.
0 para resposta № 7
Este é um erro de tempo de execução porque você já definiu a variável v
como um Car
. Você não pode converter Car
para Bike
.
O compilador não verificará este tipo de atribuição de valor porque os compiladores em geral não verificam a semântica.