Вызов метода из подкласса вызывает исключительную ситуацию ClassCastException во время выполнения.

1

Когда я запускаю исходный код ниже, ошибка выполнения, которую я вижу в окне оболочки, выглядит следующим образом:

Exception in thread "main" java.lang.ClassCastException: pkgs.main.A cannot be c
ast to pkgs.test.B
        at pkgs.main.Main.main(Main.java:9)

Должна ли эта ошибка быть захвачена компилятором во время компиляции, а не во время выполнения? Вот мои три отдельных файла исходного кода, которые коллективно компилируют ОК, без ошибок или предупреждений:

// ------------------------
// class Main, package main
// ------------------------
package pkgs.main;
import pkgs.test.B;

class Main {
    static public void main(String args[]) {
    ((B)new A()).m();  // causes runtime ClassCastException to be raised.
    }
}


// ---------------------
// class A, package main
// ---------------------
package pkgs.main;

public class A {
    public int m() { return 1; }
}


// ---------------------
// class B, package test  <--- note the different package to classes A and Main
// ---------------------
package pkgs.test;
import pkgs.main.A;

public class B extends A {
    public int m() { return 100; }
}

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

REM batch file for compilation
javac -Xlint -sourcepath ..\src -d ..\cls ..\src\pkgs\main\Main.java

REM batch file for execution
java -cp ..\cls pkgs.main.Main

Этот очень простой тестовый проект доступен для быстрой загрузки и тестирования на следующей ссылке DropBox: https://www.dropbox.com/s/60qi0vbadc5m7es/t16_mk2.7z

  • 0
    Вопрос: должна ли эта ошибка быть обнаружена компилятором во время компиляции, а не во время выполнения? `
  • 0
    попробуй ((A) new B ()). m ();
Теги:
classcastexception

4 ответа

2
Лучший ответ

Правило о том, возникает ли ошибка компиляции, приведено в 5.5.1:

Учитывая ссылочный тип времени компиляции S (источник) и тип задания времени компиляции T (target), преобразование каста существует от S до T, если ошибки времени компиляции не происходят из-за следующих правил.

Если S - тип класса:

  • Если T - тип класса, то либо | S | <: | T |, или | T | <: | S |. В противном случае возникает ошибка времени компиляции.

Это означает, что это допустимый листинг, если какой-либо тип является подклассом другого. Он работает таким образом, чтобы мы могли делать такие вещи следующим образом:

A actuallyB = new B(); // note implicit widening but could be (A)new B()
B theB = (B)actuallyB;

Человеку легко понять, что выражение (B)new A() будет бросать во время выполнения; однако для компилятора не требуется выполнение этого распознавания.

1

B является подклассом A Таким образом, экземпляр A нельзя отнести к B Возможно обратное.

B b = new B();
A a = (A)b; //valid

A a = new A();
B b = (B)a; //invalid

Возможно, вы захотите прочитать отношения IS A.

  • 1
    Вопрос: должна ли эта ошибка быть обнаружена компилятором во время компиляции, а не во время выполнения?
  • 0
    Эта ошибка должна быть обнаружена во время выполнения, потому что даже если переменная объявлена как A , она все равно может иметь тип B , поэтому приведение A к B все же имеет смысл.
Показать ещё 2 комментария
1

Должна ли эта ошибка быть захвачена компилятором во время компиляции, а не во время выполнения?

Его следует поймать во время выполнения.

Зачем?

В классе Hirearchy class B extends A, рассмотрим следующий код:

void perforAction(A obj) {
    obj.someMethodDeclaredInA();
    //more method calls from A
    if (obj instanceof B) {
        B casted = (B) obj;
        casted.someMethodDeclaredInB();
    }
}

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

0

Вы пытаетесь передать фактический объект A (который является родителем) в ссылку на объект B (которая является дочерней). Поэтому он дает ошибку.

Если бы это был фактический объект B; но ссылки как объект A; тогда литье типа было бы успешным. например

B obj_of_B = new B();
A obj_of_A = obj_of_B;
B other_obj_of_B = (B)obj_of_A;

Это будет работать правильно, как если бы ссылка на объект с именем "obj_of_A" имеет тип A, фактический объект имеет тип B.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню