Java Casting in Schnittstellen

75

Kann mir bitte jemand erklären, wie sich der Compiler im ersten Casting nicht beschwert, im zweiten aber?

interface I1 { }
interface I2 { }
class C1 implements I1 { }
class C2 implements I2 { }

public class Test{
     public static void main(){
        C1 o1 = new C1();
        C2 o2 = new C2();
        Integer o3 = new Integer(4);

        I2 x = (I2)o1; //compiler does not complain
        I2 y = (I2)o3; //compiler complains here !!
     }
}
user711189
quelle
8
Wenn Sie dies ausführen, werden Sie auf Folgendes stoßen ClassCastException: a RuntimeException.
Buhake Sindi
4
@BuhakeSindi Sie sind falsch
Andremoniy
2
@BuhakeSindi Das OP sagte, der Compiler habe sich beschwert und mir vorgeschlagen, dass Sie keine Chance bekommen, dies auszuführen.
Emory
@emory, selbst wenn er es kompilieren könnte, indem er das Element behebt, bei dem ein Compilerfehler aufgetreten ist, hätte die Zeile darüber a verursacht ClassCastException.
Buhake Sindi
1
@BuhakeSindi Du liegst falsch, weil du die Dinge sprichst, die du nicht tun solltest. Das Wasser ist nass. Es ist jedoch falsch, in diesem Zusammenhang über dieses Thema zu sprechen. Okay? Offensichtlich weiß der Fragesteller davon, weil er ein Experiment durchführt.
Val

Antworten:

148

Beim Casting o1und o3mit (I2)teilen Sie dem Compiler mit, dass die Klasse des Objekts tatsächlich eine Unterklasse des deklarierten Typs ist und dass diese Unterklasse implementiert wird I2.

Die IntegerKlasse ist endgültig und o3kann daher keine Instanz einer Unterklasse von sein Integer: Der Compiler weiß, dass Sie lügen. C1ist jedoch nicht endgültig, o1 könnte also eine Instanz eines Subtyps C1dieser Geräte sein I2.

Wenn Sie C1final machen , wird sich auch der Compiler beschweren:

interface I1 { }
interface I2 { }
final class C1 implements I1 { }
class C2 implements I2 { }

public class Test{
     public static void main(){
        C1 o1 = new C1();
        C2 o2 = new C2();
        Integer o3 = new Integer(4);

        I2 y = (I2)o3; //compiler complains here !!
        I2 x = (I2)o1; //compiler complains too
     }
}
WilQu
quelle
1
"Integer ist endgültig, also o3 als keine Chance, von Schnittstelle I2 zu sein" Das ist in dieser Form ziemlich falsch. Nicht die Bedeutung, sondern die Formulierung.
Powerslave
1
@ WilQu Ich habe mich nicht über den Tippfehler beschwert, sondern über die Formulierung der Antwort. Wenn Sie unten einen Blick darauf werfen, werden Sie sehen, wie viel klarer Etiennes Formulierung derselben Sache ist. Ihre kann missverständlich und daher irreführend sein, da Sie (zum Beispiel) nicht erwähnt haben, dass die Klasse von Integerendgültig ist (was für mich und Sie, aber wahrscheinlich nicht für alle offensichtlich ist) und der Teil "hat keine Chance, eine Schnittstelle zu sein" dies tut nicht zu viele Informationen tragen; Tatsächlich sind die fraglichen Informationen im zweiten Satz versteckt. Man könnte sogar denken, dass finalKlassen keine Inferfaces implementieren können, was nicht wahr ist.
Powerslave
@ Powerslave danke für deine Kommentare, ich habe meine Antwort erneut bearbeitet. Ich habe versucht, mehr Erklärungen hinzuzufügen, ich hoffe, dass meine Antwort dadurch nicht noch verwirrender wird.
WilQu
@ WilQu Ausgezeichnet! Es stellte sich heraus, dass es eine sehr schöne Erklärung war :)
Powerslave
35

Gemäß JLS Kapitel 5

5.5.1. Referenztyp Casting

Bei einem Referenztyp zur Kompilierungszeit S (Quelle) und einem Referenztyp zur Kompilierungszeit T (Ziel) liegt eine Casting-Konvertierung von S nach T vor, wenn aufgrund der folgenden Regeln keine Fehler zur Kompilierungszeit auftreten. Wenn T ein Schnittstellentyp ist:

Wenn S keine endgültige Klasse ist (§8.1.1), dann, wenn es einen Supertyp X von T und einen Supertyp Y von S gibt, so dass sowohl X als auch Y nachweislich unterschiedliche parametrisierte Typen sind und die Löschungen von X. und Y gleich sind, tritt ein Kompilierungsfehler auf.

Andernfalls ist die Umwandlung zur Kompilierungszeit immer legal (denn selbst wenn S T nicht implementiert, kann eine Unterklasse von S auftreten).

Wenn S eine letzte Klasse ist (§8.1.1), muss S T implementieren, da sonst ein Fehler bei der Kompilierung auftritt.

maba
quelle
23

Das liegt daran, dass der Unterricht Integerendgültig ist und C1nicht. Somit kann ein Integer-Objekt I2 nicht implementieren, während ein C1-Objekt dies könnte, wenn es eine Instanz einer Unterklasse von C1 ist, die I2 implementiert.

Etienne Miret
quelle
15

Gemäß JLS 5.5.1 - Referenztyp-Guss gelten die folgenden Regeln:

  • Wenn T ein Klassentyp ist, dann entweder | S | <: | T | oder | T | <: | S |. Andernfalls tritt ein Fehler bei der Kompilierung auf.

    I2 y = (I2)o3; //compiler complains here !!

In diesem Fall wird ein Integerund I2sind in keinem Zusammenhang in irgendeiner Weise, so dass ein Fehler bei der Kompilierung auftritt. Auch, weil Integerist final, gibt es keine Beziehung zwischen Integerund I2.

I2und I1kann in Beziehung gesetzt werden, da beide eine Markierungsschnittstelle sind (es gibt keinen Vertrag).

Für den kompilierten Code gilt folgende Regel:

  • Wenn S keine endgültige Klasse ist (§8.1.1), dann, wenn es einen Supertyp X von T und einen Supertyp Y von S gibt, so dass sowohl X als auch Y nachweislich unterschiedliche parametrisierte Typen sind und die Löschungen von X. und Y gleich sind, tritt ein Kompilierungsfehler auf.

Sist o1und Tist I2.

Hoffe das hilft.

Buhake Sindi
quelle