2014-08-29 6 views
1

Попытка следующее:Почему ClassCastException является ошибкой во время выполнения?

class Base { 
    public Base(){ 
    } 
} 

class Derived extends Base { 
} 

public class Main 
{ 
    public static void main (String[] args) 
    { 
     Derived derived = (Derived) new Base(); 
    } 
} 

Вызывает CastClassException, но успешно компилируется. Комментарии к this question предполагают, что компилятор не может понять, какой тип new Base() имеет до выполнения - но почему так должно быть? Я знаю, что в other type systems компилятор всегда может вывести тип любого выражения, а компилятор Java, конечно же, выполняет какой-либо вывод типа, например. лямбда-выражения. И в какой-то момент он должен знать, какой тип new Base() имеет, если он испустит правильный байт-код.

Есть ли теоретическое ограничение, препятствующее компилятору Java улавливать это до запуска программы или это выбор реализации?

+0

Потому что это происходит во время выполнения ?? –

+0

Casting things говорит компилятору игнорировать его собственную информацию о типе и вместо этого доверять программисту. Вот почему он этого не понимает. Компилятор говорит: «Я знаю, что это тип базы, но программист сказал, что это Derived. Они знают лучше всего». –

ответ

4
public static void main(String[] args) throws Exception { 
    Derived derived = (Derived) getObject(); 
} 

public static Base getObject() { 
    if (Math.random() > 0.5) { 
     return new Base(); 
    } else { 
     return new Derived(); 
    } 
} 

Что теперь? Как компилятор узнает? Компилятор (в основном) ограничен статической информацией. Тип объекта - это динамическая информация.

+0

Я не думал о таком случае. Мне все же кажется более разумным отклонять неоднозначные случаи - есть ли веские основания писать актеры, которые не выполняются в 50% случаев? Но я понимаю, почему, наверное. –

+0

@patrick Кастинг обычно не считается хорошей практикой. Мой пример должен был показать, что существует предел тому, что может знать компилятор. Разработчики языка должны были принять решение против специального рассмотрения случаев заболевания. –

1

Результат new Base() является Base, что в любом другом контексте может быть Derived. компилятор не распространяется на специальные знания, что в данном случае это действительно Base.

Есть теоретическое ограничение, которое не позволяет компилятору Java улавливать это до запуска программы или это выбор реализации?

Это выбор реализации, чтобы не сделать особый случай.

3

Любая рациональная реализация языка, разрешающего подклассирование, будет иметь возможность исключения исключения (или его эквивалента).

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

Возможно, вы можете скрыть исключение литья за каким-либо механизмом, который, скажем, возвращает NULL, если объект не был правильным, но это просто заменяет одно исключение другим.

+0

Да, мне нравится, как C# использует 'as'. –

Смежные вопросы