Навчання для мого 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();
Я одразу отримую помилку компіляції.
Два питання:
- Чому вищезазначений код взагалі компілюється? Здається, телефон не пов'язаний зі мною.
- Чому код компілюється з
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();
}