/ / ClassCastException проти помилки компіляції "not cast" - java, успадкування, лиття

ClassCastException vs. "не можу кинути" помилку компіляції - java, спадщина, кастинг, класневипадкування

Навчання для мого OCA Java SE 7 Програміст я іспит, так що новачок питання. У мене є приклад питання, я не розумію. Наступний код компілюється, але дає ClassCastException під час виконання:

interface Roamable {
}

class Phone {
}

public class Tablet extends Phone implements Roamable {
public static void main(String... args) {
Roamable var = (Roamable) new Phone();
}
}

Коли я зміню Roamable var = (Roamable) new Phone(); в Roamable var = (Roamable) new String(); Я одразу отримую помилку компіляції.

Два питання:

  1. Чому вищезазначений код взагалі компілюється? Здається, телефон не пов'язаний зі мною.
  2. Чому код компілюється з new Phone(), але не компілюється new String()?

Відповіді:

13 за відповідь № 1

Чому вищезазначений код взагалі компілюється? Здається, телефон не має відношення до Роумінг для мене?

так, тому що Roamable це інтерфейс, який може викликати виняток під час виконання, але не виключає час компіляції, оскільки навіть якщо Phone не реалізує Roamable, підклас Phone може, отже, компілятор не має можливості його знати, але в час виконання.

Це вже визначено в специфікації мови java. Перегляньте мою відповідь тут.

Чому код компілюється з новим Phone (), але не компілюється з новим рядком ()?

Оскільки class String оголошено як public final class в java.lang пакет. Як зазначено в jls 8.1.1.2 final class розділ: клас оголошений як final не може бути розширена і, отже, вона не матиме жодного підкласу. Отже, компілятор це вже знає String не може бути розширено: отже, існування підкласу неможливе інтерфейс Roamable

Редагувати: (у відповідь на ваш коментар нижче)

Припустимо, що B є підкласом A який реалізує інтерфейс T.

Тепер заяву:

   T t = (T)new A();

по суті таке ж, як:

   A aObj = new A() ;
T t = (T)aObj ; // a run-time exception happen

перед тим, як закінчити, давайте зробимо те ж саме з об'єктом B:

   A aObj = new B();
T t = (T)aObj; // no exception happen.

отже, справжньою причиною з суперкласом і підкласом тут є посилання. The aObj Клас у цьому другому прикладі коду також є екземпляром класу A але це також примірник класу B що реалізовано T.


3 для відповіді № 2

Рядок є остаточним, так що його не можна відкинути до Roamable.


1 для відповіді № 3

Код компілюється, оскільки компілятор дозволяєкинув до чогось. Це явна дія програміста, і компілятор припускає, що ви оцінили ризики і прийняли відповідні заходи безпеки.

String не є прикладом Roamable, тому не можна призначити примірник String до a Roamable посилання. І це може бути визначено під час компіляції, тому не вдається.


1 для відповіді № 4

new Phone() оцінюється в клас Phone, котрий міг бути розширенням Phone що реалізує Roamable (що стосується компілятора).

Якщо Ви зробили Телефон a final class (наприклад String), ви отримаєте помилку компілятора.


0 для відповіді № 5

Гарне питання. new Phone() безумовно, не будь-який підклас Phone. Однак ця інформація втрачена, javac бачить Phone тип там, не той точно Phone тип

Відповідна специфікація: http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1

Якщо S є остаточним класом (§8.1.1), то S повинна реалізувати T,

Специфікацію можна змінювати за допомогою

Якщо вираз є виразом створення екземпляра класу (§15.9), тип виразу повинен бути підтипом T.


0 для відповіді № 6

Спочатку прочитайте про Явне і неявне приведення типу по java.

Від цього користувача відповідає явнийвідкидаючи при звуженні об'єктне відношення, щоб сказати, що користувач знає і добре, вони втрачають деяку точність через це. Однак компілятор може виявити деякі явні помилкові відливання і кидання CE: Type mismatch error в деякій точці. Понад цю точку до часу виконання ClassCastException мати справу з нею.

Компілятор може виявити наступні випадки явного відливання.

class A {}
class B {}

A a = (A) new B(); //CE: Type mismatch: cannot convert from B to A
B b = (B) new A(); //compilation error (CE)

interface I {}
final class A {}
I i = (I) new A();  //compilation error

Компілятор не може виявити наступні випадки явного лиття.

class A {}
class B extends A {}
A a = (A) new B(); //Fine
B b = (B) new A(); //Runtime error; because compile time;
//compiler wont be able to tell the reference is instance of A or B.
//means this is something like below. <BR>
B b = (B) (A) new A();

Будь-який об'єкт може бути кастом до будь-якого інтерфейсу без помилки компіляції.

interface I {}
class A {}
class B extends A implements I{}

I i = (I) new A();  //Runtime error
I i = (I) new B();  //Fine

Чому це компілюється?

Посилання на інтерфейси можуть касти на будь-який об'єкт без помилки компіляції.

interface I {}
class A implements I {}
class B {}

B b = (B) getI();     //Runtime error
OR
B b = (B)(I)new A();  //Runtime error

public I getI() {
return new A();
}