2017-01-31 2 views
4

diesen einfachen Code Bedenken Sie:Casting und Vererbung in Java

class A {} 

class B extends A {} 

public class TestClass { 
    public static void main(String args[]) { 
     A[] a, a1; 
     B[] b; 
     a = new A[10]; 
     a1 = a; 
     b = new B[20]; 
     a = b; // 1 
     b = (B[]) a; // 2 
     b = (B[]) a1; // 3 
    } 
} 

Schauen Sie genau auf Linien, die ich 1,2 und 3. kommentiert Die Linie 1 wird während der Kompilierung erlaubt werden, da Zuordnung von einer Unterklasse Referenz erfolgt zu einer Superklassenreferenz.

Die Umwandlung in Zeile 2 wird benötigt, da eine Oberklassenreferenz einer Unterklassenreferenzvariablen zugewiesen wird. Und das funktioniert zur Laufzeit, weil das Objekt, auf das von a verwiesen wird, tatsächlich ein Array von B (Zeile 1) ist.

Nun, hier ist, wo liegt meine Verwirrung: Zeile 3 wird eine java.lang.ClassCastException werfen. Das bedeutet nun, dass das Programm während der Laufzeit realisiert, dass das tatsächliche Objekt kein Array von B ist, sondern ein Array von A.

Dies ist genau das, was ich nicht verstehe. Erweitert sich B nicht um A? So erfüllt es die Bedingung B IS-A A, richtig? Und sollte daher Zeile 3 während der Laufzeit keine Ausnahme auslösen?

+1

Bitte nehmen Sie sich die Zeit, um den von Ihnen bereitgestellten Code zu formatieren. Es ist * wirklich, wirklich * schwer im Moment zu lesen, ohne Einrückung und mehrere Anweisungen in einer Zeile. Bitte bedenken Sie, dass der Zweck von Stack Overflow darin besteht, eine Sammlung von qualitativ hochwertigen Fragen und Antworten zu erstellen - geben Sie die Zeit an, um Ihre Frage wirklich hochwertig zu machen. –

+1

"So erfüllt es die Bedingung B IS-A A, richtig?" Richtig. Aber was du brauchst, ist "A IS-A B" - aber das hast du nicht. Ich denke, die Verwirrung ist von hier: 'a1 = a; a = b; // 1' - durch Ändern des Verweises 'a' ändert sich' a1' nicht **. Es zeigt immer noch auf das gleiche 'A []'. – Fildor

Antwort

7

a1 ist ein Array von A Elementen. Da BA erweitert, sind alle Instanzen von B auch Instanzen von A, aber nicht alle Instanzen von A sind Instanzen von B. Sie könnten eine Klasse C definieren, die auch A erweitert und Instanzen dieser Klasse dem Array a1 zuweisen. Solche Instanzen sind keine Instanzen von B.

Daher können Sie kein Array von A Elementen in ein Array von B Elementen übertragen.

+0

Aber der Code kompiliert gut. Es löst zur Laufzeit eine Ausnahme aus. Nehmen wir an, ich habe ein Array wie folgt erstellt: "TestClass c [] = new TestClass [20]". Wenn ich jetzt 'b = (B []) c' versuche, kompiliert es sich nicht und sagt ** inkompatible Typen **. Warum gibt es unterschiedliche Verhaltensweisen? –

+0

@Shashwat Sie können einer A [] - Variablen eine B [] - Instanz zuweisen (genau wie Sie einer A - Variablen eine B - Instanz zuweisen können). Daher kann das Umwandeln einer A [] - Variable in B [] (oder eine A-Variable in B) in der Laufzeit erfolgreich sein, wenn die Laufzeittypen übereinstimmen. Eine TestClass [] kann jedoch nie in B [] umgewandelt werden, da TestClass keine Unterklasse von B ist und B keine Unterklasse von TestClass ist. Deshalb lässt der Compiler das nicht zu. – Eran

+0

Lass mich das klarstellen. Obwohl Sie 'b = (B []) a1 nicht machen können;', 'b' und' a1' sind kompatible Typen und das ist alles, wonach der Compiler sucht, also kompiliert es korrekt, obwohl es tatsächlich unmöglich ist, 'b' zuzuweisen gleich 'a1'. Bitte korrigiere mich wenn ich falsch liege,. –

0

Sie haben Recht, wenn er sagt "B IS-A A" und deshalb
i) Es gibt keine Frage, wenn man a = b setzen;
ii) Es gibt kein Problem bei der Kompilierung für Anweisung # 3

Aber Sie können nicht sagen "A IS-A B", also die Laufzeit Ausnahme.

2

Sie haben vergessen, dass Arrays selbst Klassen sind, und sie haben ihre eigenen Darstellungs- und Zuweisungsregeln.

Bedenken Sie:

A[] aa = new A[0]; 
    B[] bb = new B[0]; 

    System.out.println(aa.getClass()); 
    System.out.println(bb.getClass()); 

    System.out.println(aa.getClass().isAssignableFrom(bb.getClass())); 
    System.out.println(bb.getClass().isAssignableFrom(aa.getClass())); 

Ausgang:

class [Lstuff.small.Try47$A; 
class [Lstuff.small.Try47$B; 
true 
false 

So ein A [] Variable in der Tat einen B [] zugeordnet werden kann, aber nicht umgekehrt.