В Java разрешена повышающая передача, однако понижающая передача приводит к ошибке компиляции.
Ошибка компиляции может быть устранена путем добавления приведения, но в любом случае она прервется во время выполнения.
В таком случае, почему Java допускает даункастинг, если он не может быть выполнен во время выполнения? Есть ли какое-либо практическое применение этой концепции?
publicclassdemo { publicstaticvoidmain(String a[]) { Bb= (B) newA(); // compiles with the cast, // but runtime exception - java.lang.ClassCastException } }
Понижающая обработка допускается, когда есть вероятность, что она завершится успешно во время выполнения:
Objecto= getSomeObject(), Strings= (String) o; // this is allowed because o could reference a String
В некоторых случаях это не приведет к успеху:
Objecto=newObject(); Strings= (String) o; // this will fail at runtime, because o doesn't reference a String
При сбое приведения (такого, как это последнее) во время выполнения будет выдан a ClassCastException.
В других случаях это будет работать:
Objecto="a String"; Strings= (String) o; // this will work, since o references a String
Обратите внимание, что некоторые приведения будут запрещены во время компиляции, потому что они вообще никогда не будут успешными:
Integeri= getSomeInteger(); Strings= (String) i; // the compiler will not allow this, since i can never reference a String.
Ответ 2
Используя ваш пример, вы могли бы сделать:
publicvoiddoit(A a) { if(a instanceof B) { // needs to cast to B to access draw2 which isn't present in A // note that this is probably not a good OO-design, but that would // be out-of-scope for this discussion :) ((B)a).draw2(); } a.draw(); }
Ответ 3
Я считаю, что это применимо ко всем статически типизированным языкам:
Strings="some string"; Objecto= s; // ok Stringx= o; // gives compile-time error, o is not neccessarily a string Stringx= (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String
Приведение типов фактически говорит: предположим, что это ссылка на класс приведения, и используйте его как таковой. Теперь предположим, что o является действительно целым числом, предположение, что это строка, не имеет смысла и даст неожиданные результаты, поэтому должна быть проверка во время выполнения и исключение, уведомляющее среду выполнения, что что-то не так.
При практическом использовании вы можете написать код, работающий с более общим классом, но привести его к подклассу, если вы знаете, что это за подкласс, и вам нужно относиться к нему как к таковому. Типичным примером является переопределение Object.equals() . Предположим, у нас есть класс для Car:
@Override booleanequals(Object o) { if(!(o instanceof Car)) returnfalse; Carother= (Car)o; // compare this to other and return }
Ответ 4
Мы все видим, что предоставленный вами код не будет работать во время выполнения. Это потому, что мы знаем, что выражение new A() никогда не может быть объектом типа B.
Но компилятор видит это не так. К тому времени, когда компилятор проверяет, разрешено ли приведение, он просто видит это:
variable_of_type_B = (B)expression_of_type_A;
И, как продемонстрировали другие, такое приведение совершенно законно. Выражение справа вполне может быть преобразовано в объект типа B. Компилятор видит, что A и B имеют отношение к подтипу, поэтому с представлением кода "выражение" приведение может сработать.
Компилятор не учитывает особый случай, когда он точно знает, какой тип объекта expression_of_type_A действительно будет иметь. Он просто видит статический тип как A и считает, что динамическим типом может быть A или любой потомок A, включая B.