Следният кодов фрагмент ще доведе до изпълнение:
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();
}
}
Моят въпрос е: защо това води до грешка по време на изпълнение, но не и компилационна грешка? Не трябва ли компилаторът да знае, че "v" вече е "Car" и не може да бъде хвърлен в "Bike"?
Отговори:
9 за отговор № 1На теория е възможно компилаторът да каже на себе си: "v
е локална променлива, която е присвоена на a Car
, В нито един момент преди опита да се направи Bike
променя ли стойността си и няма начин Car
за да бъдете успешно хвърлени Bike
, Следователно това е грешка. "
Въпреки това, знам, че няма да има никакъв Java компилатортози анализ за вас. Това е наистина полезно само в най-простия случай. Vehicle
до a Bike
, и така го позволява.
Най-общо казано, това означава: той казва на компилатора, че въпреки че това присвояване може да се провали, ти си доста сигурен, че е спечелил. В замяна, за да позволи на кода да се компилира, вие поемате риска от изключение по време на изпълнение.
4 за отговор № 2
Кастинг от супер клас може да работи, така че е позволено (по време на компилация). Кастингът от напълно различен клас не е разрешен, например:
Integer a = 1;
String b = (String)a; // compile error
String b = (String)(Object)a; // runtime error
3 за отговор № 3
За
R r = /* some code to initialize "r" */
T t = (T) r;
Най- Спецификация за език на Java казва:
Ако R е обикновен клас (не клас масив):
- Ако T е тип клас, тогава R трябва да бъде или същия клас като T или подклас от T, или да се хвърли изключение по време на изпълнение.
- Ако T е тип интерфейс, тогава R трябва да въведе интерфейс T или да бъде хвърлено изключение по време на изпълнение.
- Ако T е тип масив, тогава се хвърля изключение по време на изпълнение.
1 за отговор № 4
Въвеждането на обекта се извършва по време на изпълнение, така че компилаторът не го разпознава
0 за отговор № 5
Не. v
е Vehicle
и може да е възможно да го хвърлим Bike
, Това не е работата на компилатора, за да разбере действителните видове изпълнения на всеки обект (особено защото понякога това е невъзможно).
0 за отговор № 6
Семантиката на Java казва, че това трябва да доведе до товапри грешка по време на изпълнение. В този случай е възможно да погледнете кода и да видите, че той определено ще хвърли грешка по време на изпълнение, но как компилаторът знае, че ClassCastException
не е това, което искаш?
Редакторите като IntelliJ и Eclipse могат (и правят) да забележат такива грешки и да ви предупредят за тях, но правилата на Java казват, че това е законен код, който трябва да се компилира.
0 за отговор № 7
Това е грешка по време на изпълнение, защото вече сте дефинирали променливата v
като Car
, Не можете да конвертирате Car
да се Bike
.
Компилаторът няма да провери този тип присвояване на стойност, защото компилаторите като цяло не проверяват семантиката.