Downcasting en Java
Upcasting est autorisé en Java, cependant downcasting donne une erreur de compilation.
l'erreur de compilation peut être supprimée en ajoutant un cast, mais se briserait de toute façon à l'exécution.
dans ce cas, pourquoi Java autorise la downcasting si elle ne peut pas être exécutée à l'exécution?
Ce concept a-t-il une utilité pratique?
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 réponses
Passer est autorisé lorsqu'il y a une possibilité qu'il réussit au moment de l'exécution:
Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String
Dans certains cas, cela ne réussira pas:
Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String
dans d'autres il fonctionnera:
Object o = "a String";
String s = (String) o; // this will work, since o references a String
Lorsqu'un moulage (comme celui-ci) échoue à l'exécution, un ClassCastException
sera lancé.
notez que certaines distributions seront refusées au moment de la compilation, car elles jamais réussir du tout:
Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
en utilisant votre exemple, vous pouvez faire:
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();
}
je crois que cela s'applique à tous les langages statiquement typés:
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
le typecast dit effectivement: supposons qu'il s'agisse d'une référence à la classe de fonte et utilisez-la comme telle. Maintenant, disons que o est vraiment un entier, en supposant qu'il s'agisse d'une chaîne de caractères n'a aucun sens et donnera des résultats inattendus, donc il faut qu'il y ait une vérification d'exécution et une exception pour notifier à l'environnement d'exécution que quelque chose ne va pas.
In utilisation pratique, vous pouvez écrire du code travaillant sur une classe plus générale, mais jetez-le dans une sous-classe si vous savez de quelle sous-classe il s'agit et si vous avez besoin de le traiter comme tel. Un exemple typique est primordial d'Objet.égal.)( Supposons que nous ayons une classe pour la voiture:
@Override
boolean equals(Object o) {
if(!(o instanceof Car)) return false;
Car other = (Car)o;
// compare this to other and return
}
nous pouvons tous voir que le code que vous avez fourni ne fonctionnera pas à l'exécution. C'est parce que nous savons que l'expression new A()
peut jamais être un objet de type B
.
mais ce n'est pas comme ça que le compilateur le voit. Au moment où le compilateur vérifie si la distribution est autorisée, il voit juste ceci:
variable_of_type_B = (B)expression_of_type_A;
Et comme d'autres l'ont démontré, ce genre de casting est parfaitement légal. Expression sur la droite, pourrait très bien correspondre à un objet de type B
. Le compilateur voit que A
et B
ont une relation de sous-Type, donc avec la vue "expression" du code, la distribution pourrait fonctionner.
le compilateur ne considère pas le cas spécial quand il sait exactement quel type d'objet expression_of_type_A
aura vraiment. Il voit juste le type statique A
et considère le type dynamique pourrait être A
ou tout descendant de A
, y compris B
.
dans ce cas, pourquoi Java autorise la downcasting si elle ne peut pas être exécutée à l'exécution?
je crois que c'est parce qu'il n'y a aucun moyen pour le compilateur de savoir au moment de la compilation si la distribution réussira ou non. Pour votre exemple, il est simple de voir que la distribution va échouer, mais il ya d'autres moments où il n'est pas si clair.
par exemple, imaginez que les types B, C, et D Tous étendent le type A, puis une méthode public A getSomeA()
renvoie une instance de B, C ou d en fonction d'un nombre généré au hasard. Le compilateur ne peut pas savoir quel type exact run-time sera retourné par cette méthode, donc si vous lancez plus tard les résultats sur B
, il n'y a aucun moyen de savoir si la distribution réussira (ou échouera). Par conséquent, le compilateur doit assumer jette réussira.
@ affiche originale - voir les commentaires en ligne.
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 fonctionne dans le cas où nous avons affaire à un objet upcasted. Upcasting:
int intValue = 10;
Object objValue = (Object) intvalue;
donc maintenant cette variable objValue
peut toujours être réduite à int
parce que l'objet qui a été moulé est un Integer
,
int oldIntValue = (Integer) objValue;
// can be done
mais parce que objValue
est un objet qu'il ne peut pas être moulé à String
parce que int
ne peut pas être moulé à String
.
Passer est très utile dans l'extrait de code suivant que j'utilise tout le temps. Prouvant ainsi que de passer est utile.
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;
}
je stocke la chaîne dans la liste liée. Lorsque je récupère les éléments de la liste liée, les objets sont retournés. Pour accéder aux éléments en tant que Chaînes(ou tout autre objet de classe), downcasting m'aide.
Java nous permet de compiler du code downcast en nous faisant confiance que nous faisons la mauvaise chose. Encore si les humains font une erreur, il est pris à la course.
considérons l'exemple ci-dessous
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");
}
}
nous créons ici l'objet de la sous-classe Bone et nous l'assignons à un renvoi de super classe AOne et maintenant le renvoi de superclasse ne sait pas à propos de la méthode method2 dans la sous-classe I. e os pendant la compilation.par conséquent, nous devons réduire ce renvoi de la superclasse au renvoi de la sous-classe afin que le renvoi résultant puisse connaître la présence de méthodes dans la sous-classe I. e os 151920920"