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");
}
}
794   9  

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 String

typecast эффективно говорит: предположим, что это ссылка на класс 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

    Ничего не найдено.