Downcasting на Java
Upcasting разрешен в Java, однако downcasting дает ошибку компиляции.
ошибка компиляции может быть удалена путем добавления приведения, но в любом случае сломается во время выполнения.
в этом случае, почему Java позволяет downcasting, если он не может быть выполнен во время выполнения?
Есть ли практическое применение этой концепции?
public class demo {
public static void main(String a[]) {
B b = (B) new A(); // compiles with the cast,
// but runtime exception - java.lang.ClassCastException
}
}
class A {
public void draw() {
System.out.println("1");
}
public void draw1() {
System.out.println("2");
}
}
class B extends A {
public void draw() {
System.out.println("3");
}
public void draw2() {
System.out.println("4");
}
}
9 ответов:
приведения типов допускается, когда есть вероятность, что это удастся во время выполнения:
Object o = getSomeObject(), String s = (String) o; // this is allowed because o could reference a Stringв некоторых случаях это не удастся:
Object o = new Object(); String s = (String) o; // this will fail at runtime, because o doesn't reference a Stringв других это будет работать:
Object o = "a String"; String s = (String) o; // this will work, since o references a Stringкогда приведение (например, это последнее) терпит неудачу во время выполнения a
ClassCastExceptionбудет брошен.обратите внимание, что некоторые приведения будут запрещены во время компиляции, потому что они никогда не будут успешными:
Integer i = getSomeInteger(); String s = (String) i; // the compiler will not allow this, since i can never reference a String.
используя Ваш пример, вы могли бы сделать:
public void doit(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(); }
Я считаю, что это относится ко всем статически типизированные языки:
String s = "some string"; Object o = s; // ok String x = o; // gives compile-time error, o is not neccessarily a string String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a Stringtypecast эффективно говорит: предположим, что это ссылка на класс cast и использовать его как таковой. Теперь, скажем, o-это действительно целое число, предполагая, что это строка не имеет смысла и даст неожиданные результаты, таким образом, должна быть проверка времени выполнения и исключение, чтобы уведомить среду выполнения, что что-то не так.
в практической пользе, вы можете написать работу кода на более общем классе, но приведите его к подклассу, если вы знаете, что это за подкласс, и должны рассматривать его как таковой. Типичным примером является переопределение объекта.равняется.)( Предположим у нас есть класс для автомобиля:
@Override boolean equals(Object o) { if(!(o instanceof Car)) return false; Car other = (Car)o; // compare this to other and return }
мы все видим, что код, который вы предоставили не работает во время выполнения. Это потому, что мы знаем, что выражение
new A()can никогда быть объектом типаB.но компилятор видит это не так. К тому времени, когда компилятор проверяет, разрешено ли приведение, он просто видит это:
variable_of_type_B = (B)expression_of_type_A;и, как показали другие, такой бросок совершенно законен. Выражение справа может очень хорошо оценить объект типа
B. Компилятор видит, чтоAиBимеют отношение подтипа, поэтому с представлением" выражение " кода приведение может работать.компилятор не рассматривает частный случай, когда он знает ровно какой объект типа
expression_of_type_Aдействительно есть. Он просто видит статический тип какAи считает, что динамический тип может бытьAили любой потомокA, включаяB.
в этом случае, почему Java позволяет downcasting, если он не может быть выполнен во время выполнения?
Я считаю, что это потому, что компилятор не может знать во время компиляции, будет ли приведение успешным или нет. Для вашего примера легко увидеть, что бросок потерпит неудачу, но есть и другие времена, когда это не так ясно.
например, представьте, что типы B, C и D все расширяют тип A, а затем метод
public A getSomeA()возвращает экземпляр либо B, C или D в зависимости от случайно сгенерированного числа. Компилятор не может знать, какой именно тип времени выполнения будет возвращен этим методом, поэтому если вы позже приведете результаты кB, нет никакого способа узнать, будет ли приведение успешным (или неудачным). Поэтому компилятор должен предположить, что приведения будут успешными.
@ оригинальный плакат - см. встроенные комментарии.
public class demo { public static void main(String a[]) { B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException //- A subclass variable cannot hold a reference to a superclass variable. so, the above statement will not work. //For downcast, what you need is a superclass ref containing a subclass object. A superClassRef = new B();//just for the sake of illustration B subClassRef = (B)superClassRef; // Valid downcast. } } class A { public void draw() { System.out.println("1"); } public void draw1() { System.out.println("2"); } } class B extends A { public void draw() { System.out.println("3"); } public void draw2() { System.out.println("4"); } }
Downcast работает в том случае, когда мы имеем дело с объектом upcasted. Upcasting:
int intValue = 10; Object objValue = (Object) intvalue;так вот этот
objValueпеременная всегда может быть понижена доintпотому что объект который был отлит являетсяInteger,int oldIntValue = (Integer) objValue; // can be doneа потому что
objValueобъект не может быть приведен кString, потому чтоintне может быть приведен кString.
Downcasting очень полезен в следующем фрагменте кода я использую это все время. Тем самым доказав, что приведения типов является полезным.
private static String printAll(LinkedList c) { Object arr[]=c.toArray(); String list_string=""; for(int i=0;i<c.size();i++) { String mn=(String)arr[i]; list_string+=(mn); } return list_string; }Я храню строку в связанном списке. Когда я получаю элементы связанного списка, объекты возвращаются. Чтобы получить доступ к элементам в виде строк(или любых других объектов класса), мне помогает downcasting.
Java позволяет нам компилировать код downcast, доверяя нам, что мы делаем не то. Тем не менее, если люди ошибаются, это так поймали во время выполнения.
рассмотрим следующий пример
public class ClastingDemo { /** * @param args */ public static void main(String[] args) { AOne obj = new Bone(); ((Bone) obj).method2(); } } class AOne { public void method1() { System.out.println("this is superclass"); } } class Bone extends AOne { public void method2() { System.out.println("this is subclass"); } }здесь мы создаем объект подкласса Bone и назначаем его суперклассу AOne reference и теперь суперкласс reference не знает о методе method2 в подклассе т. е. кости во время компиляции.поэтому нам нужно понизить эту ссылку суперкласса на ссылку подкласса, чтобы результирующая ссылка могла знать о наличии методов в подклассе, т. е. Bone
Comments