Das verwirrt eine Menge Leute. Lass mich versuchen, es zu durchbrechen. Wenn Sie new Square
sagen, wird das Objekt mit dem Konstruktor Square
erstellt. Das Objekt wird während seiner gesamten Existenz den Typ Square
haben.
Wenn Sie eine Variable mit Typ deklarieren Rectangle
, das heißt Rectangle x;
oder Rectangle x = (anything);
Sie sagen dem Compiler, dass x
(wenn es nicht null ist) wird ein Verweis auf Rectangle
oder einer ihrer Unterklassen (einschließlich Square
) immer sein. Wenn Sie Rectangle x = new Square(...)
sagen, wird x
eine Referenz auf eine Square
sein, die eine Rectangle
ist. Jedoch könnte, x
später neu zugewiesen werden, um ein anderer Rectangle
zu werden, der kein Square
ist. nur
Das bedeutet, dass, wenn Sie x.method(...)
sagen, nur die Compiler Sie die Methoden verwenden kann, die in Rectangle
definiert sind, weil der Compiler weiß, dass x
ein Rectangle
oder eine Unterklasse. Wenn Sie eine neue Methode in Square
deklarieren, können Sie sie mit dem obigen Aufruf nicht verwenden.
Wenn jedoch x
noch ist ein Verweis auf eine Square
, dann, wenn Sie eine Methode in Rectangle
definiert nennen, wird das Programm tatsächlich die Methode laufen Sie für Square
geschrieben (wenn Sie die eine in Rectangle
außer Kraft gesetzt haben).
Vielleicht hilft dieses Beispiel. Angenommen, Rectangle
deklariert public
Methoden aaa
und bbb
. In Square
schreiben Sie eine überschreibende Methode , überschreiben Sie nicht bbb
, und Sie deklarieren eine neue öffentliche Methode ccc
.
Rectangle x = new Square(10);
Rectangle y = new Rectangle(5,6);
// assume that x and y aren't changed
x.aaa(); // runs the overriding method aaa in Square
y.aaa(); // runs the method aaa in Rectangle
x.bbb(); // runs the method in Rectangle, since it's not overridden. But
// if bbb calls aaa, then it will call the aaa in Square.
y.bbb(); // runs the method in Rectangle
x.ccc(); // illegal. Even though the object is actually a Square, the
// compiler isn't allowed to know that.
y.ccc(); // illegal
((Square)x).ccc(); // This is how you can get to the new method that you
// declared in Square. Even though the compiler doesn't know
// that x is a Square, when you use the cast, you tell the
// compiler that it's OK fo treat it as a Square, and to access
// the method defined only in Square.
((Square)y).ccc(); // Will throw ClassCastException at runtime, because
// y isn't a Square.
Hoffe, das hilft.
Nebenbei, "Square erweitert Rectangle" kann keine gute Idee sein. Es stimmt zwar, dass in der Geometrie ein Quadrat ein Rechteck ist, was die API nicht betrifft. Ein Rechteck hat wahrscheinlich 'setHeight'- und' setWidth'-Methoden, mit der Annahme, dass die Einstellung von Eins sich nicht auf die andere auswirkt. Aber ein Square genauso wie 'setLength', was sowohl die Höhe als auch die Breite betrifft.Selbst wenn Sie die Methodennamen teilen, ist das Verhalten so unterschiedlich, dass es wahrscheinlich nicht gut ist, Square extend Rectangle zu haben. – yshavit
@yshavit: Solange Länge und Breite gleich sind, unterscheidet sich ein Quadrat im Prinzip nicht von einem Rechteck. – Makoto
@Makoto Wenn Sie ein 'Rectangle rect' mit width = 5 und height = 5 hätten, und Sie' rect.setHeight (2) 'aufgerufen hätten, was würden Sie von' rect.getWidth() 'erwarten? Ich würde erwarten, dass es bei 5 bleibt und nicht auf 2 geändert wird. Nun würde vielleicht ein sorgfältiges Lesen der JavaDocs etwas wie "Ändern der Breite kann oder nicht auch die Höhe ändern" offenbaren, aber (a) das ist [einfach zu verpassen] (https://www.wikiwand.com/en/Principle_of_least_astonishment) und (b) das macht es schwieriger, über dein Programm nachzudenken, da du mehr "vielleicht" in deinem Kopf behalten musst. – yshavit