Downcasting in Java

Upcasting is toegestaan ​​in Java, maar downcasting geeft een compileerfout.

De compileerfout kan worden verwijderd door een cast toe te voegen, maar zou tijdens runtime toch breken.

Waarom staat Java in dit geval downcasting toe als het niet tijdens runtime kan worden uitgevoerd?
Is er enig praktisch nut voor dit concept?

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

Antwoord 1, autoriteit 100%

Downcasting is toegestaan ​​wanneer de mogelijkheid bestaat dat het tijdens runtime lukt:

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

In sommige gevallen zal dit niet lukken:

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

Als een cast (zoals deze laatste) tijdens runtime mislukt, a ClassCastExceptionwordt gegenereerd.

In andere gevallen zal het werken:

Object o = "a String";
String s = (String) o; // this will work, since o references a String

Houd er rekening mee dat sommige casts niet zijn toegestaan ​​tijdens het compileren, omdat ze nooit zullen slagen:

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.

Antwoord 2, autoriteit 5%

Met uw voorbeeld zou u het volgende kunnen doen:

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();
}

Antwoord 3, autoriteit 5%

Ik geloof dat dit van toepassing is op alle statisch getypeerde talen:

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

De typecast zegt in feite: neem aan dat dit een verwijzing is naar de cast-klasse en gebruik deze als zodanig. Laten we nu zeggen dat o echteen geheel getal is, ervan uitgaande dat dit een string is, heeft geen zin en geeft onverwachte resultaten, dus er moet een runtime-controle en een uitzondering zijn om de runtime-omgeving te melden dat er iets is fout.

In praktisch gebruik kun je code schrijven die werkt aan een meer algemene klasse, maar deze naar een subklasse casten als je weet welke subklasse het is en deze als zodanig moet behandelen. Een typisch voorbeeld is het overschrijven van Object.equals(). Stel dat we een klasse voor auto hebben:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}

Antwoord 4, autoriteit 2%

We kunnen allemaal zien dat de door u verstrekte code niet werkt tijdens runtime. Dat komt omdat we weten dat de uitdrukking new A()nooiteen object van het type Bkan zijn.

Maar zo ziet de compiler het niet. Tegen de tijd dat de compiler controleert of de cast is toegestaan, ziet hij dit:

variable_of_type_B = (B)expression_of_type_A;

En zoals anderen hebben aangetoond, is dat soort cast volkomen legaal. De uitdrukking aan de rechterkant zou heel goed kunnen evalueren naar een object van het type B. De compiler ziet dat Aen Been subtype-relatie hebben, dus met de “expressie”-weergave van de code zou de cast kunnen werken.

De compiler houdt geen rekening met het speciale geval wanneer hij preciesweet welk objecttype expression_of_type_Awerkelijk zal hebben. Het ziet het statische type gewoon als Aen beschouwt het dynamische type als Aof een afstammeling van A, inclusief B.


Antwoord 5

Waarom staat Java in dit geval downcasting toe als het niet tijdens runtime kan worden uitgevoerd?

Ik denk dat dit komt omdat de compiler tijdens het compileren niet kan weten of de cast zal slagen of niet. Voor jouw voorbeeld is het eenvoudig om te zien dat de cast zal mislukken, maar er zijn andere momenten waarop het niet zo duidelijk is.

Stel je bijvoorbeeld voor dat typen B, C en D allemaal type A uitbreiden, en dan retourneert een methode public A getSomeA()een instantie van B, C of D, afhankelijk van een willekeurig gegenereerd nummer. De compiler kan niet weten welk exacte runtime-type door deze methode wordt geretourneerd, dus als u de resultaten later naar Bcast, is er geen manier om te weten of de cast zal slagen (of mislukken). Daarom moet de compiler ervan uitgaan dat het casten zal lukken.


Antwoord 6

@ Originele poster – zie inline opmerkingen.

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

Antwoord 7

Downcast werkt in het geval dat we te maken hebben met een upcasted object.
Upcasting:

int intValue = 10;
Object objValue = (Object) intvalue;

Dus nu kan deze objValue-variabele altijd worden gedowncast naar intomdat het object dat werd gecast een Integeris,

int oldIntValue = (Integer) objValue;
// can be done 

maar omdat objValueeen Object is, kan het niet worden gecast naar Stringomdat intniet kan worden gecast naar String.


Antwoord 8

Downcasting is erg handig in het volgende codefragment dat ik altijd gebruik. Dus bewijzen dat downcasting nuttig is.

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;
}

Ik sla String op in de gekoppelde lijst.
Wanneer ik de elementen van de gekoppelde lijst ophaal, worden objecten geretourneerd. Om toegang te krijgen tot de elementen als Strings (of andere Class Objects), helpt downcasting me.

Java stelt ons in staat om downcast-code te compileren in het vertrouwen dat we het verkeerde doen.
Maar als mensen een fout maken, wordt deze tijdens runtime opgemerkt.


Antwoord 9

Om downcasting in Java uit te voeren en runtime-uitzonderingen te vermijden, neemt u een verwijzing naar de volgende code:

if (animal instanceof Dog) {
  Dog dogObject = (Dog) animal;
}

Hier is Dier de bovenliggende klasse en Hond de onderliggende klasse.
instanceofis een trefwoord dat wordt gebruikt om te controleren of een referentievariabele een bepaald type objectreferentie bevat of niet.


Antwoord 10

Downcasting van objecten is niet mogelijk.
Alleen

DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);

is mogelijk

class DownCasting0 {
    public int qwe() {
        System.out.println("DownCasting0");
        return -0;
    }
}
class DownCasting1 extends DownCasting0 {
    public int qwe1() {
        System.out.println("DownCasting1");
        return -1;
    }
}
class DownCasting2 extends DownCasting1 {
    public int qwe2() {
        System.out.println("DownCasting2");
        return -2;
    }
}
public class DownCasting {
    public static void main(String[] args) {
        try {
            DownCasting0 downCasting0 = new DownCasting0();
            DownCasting1 downCasting1 = new DownCasting1();
            DownCasting2 downCasting2 = new DownCasting2();
            DownCasting0 a1 = (DownCasting0) downCasting2;
            a1.qwe(); //good
            System.out.println(downCasting0 instanceof  DownCasting2);  //false
            System.out.println(downCasting1 instanceof  DownCasting2);  //false
            System.out.println(downCasting0 instanceof  DownCasting1);  //false
            DownCasting2 _downCasting1= (DownCasting2)downCasting1;     //good
            DownCasting1 __downCasting1 = (DownCasting1)_downCasting1;  //good
            DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException
            if(downCasting0 instanceof  DownCasting2){ //false
                DownCasting2 a2 = (DownCasting2) downCasting0;
                a2.qwe(); //error
            }
            byte b1 = 127;
            short b2 =32_767;
            int b3 = 2_147_483_647;
//          long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
            long b4 = 9_223_372_036_854_775_807L;
//          float _b5 = 3.4e+038; //double default
            float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
            double b6 = 1.7e+038;
            double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits
            long c1 = b3;
            int c2 = (int)b4;
            //int       4 bytes     Stores whole numbers from -2_147_483_648 to 2_147_483_647
            //float     4 bytes     Stores fractional numbers from 3.4e?038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
            float c3 = b3; //logic error
            double c4 = b4; //logic error
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here

nineteen − 16 =

Other episodes