2016-04-02 3 views
0

Zum Beispiel, wenn ich eine Klasse Rectangle und eine Klasse Square haben. Wenn die Klasse Square Rectangle erweitert, ist das Klassenquadrat eine Unterklasse der Klasse Rectangle. Jetzt sag ich hatte den Code. Rectangle shape = new Square(5,6); Ich würde ein Objekt erstellen, aber wäre es Typ Rectangle, aber mit dem Konstruktor von Quadrat oder ein Objekt von Square ?, meine Verwirrung beginnt mit der Klasse Square hat die gleichen Methoden der Klasse Rectangle, aber es wird die Methoden verwenden in der Klasse Square nicht Klasse Rectangle. Also habe ich ein Objekt von Square erstellt, aber habe Rectangle?Java. Typ vs Objekt einer Klasse

Kommentar: Jeder wird ärgerlich wissen, dass Quadrat Rechteck nicht erweitert, aber das war mein Lehrer Beispiel rein Vererbung, Infact am Ende zeigte er, wie wenn wir diesen Code verwenden, erstellt es einen Fehler.

+2

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

+0

@yshavit: Solange Länge und Breite gleich sind, unterscheidet sich ein Quadrat im Prinzip nicht von einem Rechteck. – Makoto

+0

@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

Antwort

2

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 Rectangleoder 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.

+0

Vielen Dank, dies beantwortet alle meine Fragen: D – stackflow420

+0

@ stackflow420 Wenn Sie diese Antwort am besten auf Ihre Fragen gerichtet sind, sollten Sie es als die Antwort markieren. Derzeit ist die akzeptierte Antwort zu dieser Frage Epsilon_s, was bedeutet, dass das, was Sie gesagt haben, am hilfreichsten ist. Es bedeutet auch, dass es die höchste Antwort auf dieser Seite ist und somit am sichtbarsten für alle anderen, die von einer Suchmaschine darauf stoßen. – yshavit

+0

Oh, ich möchte seine runterladen, wops: D. – stackflow420

-2

Das heißt Polymorphie, machen Sie Ihre Hausaufgaben. Die Formvariable ist nur eine Referenz, aber das reale Objekt ist ein quadratisches Objekt.

0

Vererbung gibt Ihren Objekten immer eine is-a relationship. Also, aufgrund Square Erweiterung Rectangle, ist es sicher zu sagen, dass ein Squareist-ein .

Sie haben eine Instanz von Square erstellt, aber Sie können nur die Methoden verwenden, die von ihrem übergeordneten Element Rectangle bereitgestellt werden.

+0

Sie sagen also, Sie können Methoden, die zu Square gehören, nicht aufrufen? – pczeus

+0

Wenn Sie die Instanz dieses 'Square' als' Rectangle' bezeichnen, ist das richtig. Da die Elternklasse die Methoden der Kindklasse nicht kennt, kann nichts, was das Kind definiert, vom Elternteil verwendet werden. – Makoto

1

Sie haben ein Objekt vom Typ Square erstellt.

Ein Anruf an new Foo(...) wird immer schaffen ein Foo, keine Ausnahmen. Und es wird immer den Konstruktor für Foo aufrufen, wiederum ohne Ausnahmen. Das heißt, wenn Foo von einer anderen Klasse ausgeht, dann ist der erste Konstrukteur von Foo, den Konstruktor der Oberklasse aufzurufen. Auch hier gibt es keine Ausnahmen, obwohl Sie es nicht unbedingt im Code sehen werden, denn wenn Sie keinen Aufruf an super(...) haben und in der Super-Klasse ein Konstruktor ohne Argumente vorhanden ist, dann der Compiler wird automatisch diesen Konstruktor für Sie aufrufen. Aber auf die eine oder andere Art wird es immer aufgerufen.

Da Sie festgelegt haben, dass ein Quadrat ein Rechteck ist, ist dieses Objekt auch eine Instanz von Rectangle. Bei Ihren Klassen ist ein Quadrat immer ein Rechteck, aber nicht alle Rechtecke sind Quadrate.

Das Bit Rectangle shape bedeutet nur, dass, soweit der Compiler weiß, es "mindestens" ein Rechteck ist. Es kann genau ein Rectangle sein, oder es kann eine Unterklasse von Rectangle (wie Square) sein - aber es wird nicht zum Beispiel eine Zahl sein.

Wenn Sie anrufen shape.getArea() (zum Beispiel), wird die JVM die tatsächlichen Art von shape nachschlagen - nicht nur seinen Kompilierung-Typ, aber die Art es als tatsächlich erstellt wurde, wenn Sie new aufgerufen - und rufen Sie die Methode, die diese Klasse definiert.

0

Was Sie suchen, ist die Antwort auf Frage "Ist Square wirklich ein Rechteck?". Aus der Perspektive der Gemoetrie ist die Antwort ja, aber aus der Perspektive der Softwareperspektive kann die Antwort nicht so offensichtlich sein. "Is-a" -Beziehung muss Liskov Substitution principle folgen.

Also im Wesentlichen, wenn die Basisklasse einige Methoden hat, die nicht für die abgeleitete Klasse anwendbar sind, dann ist es keine "ist-a" -Beziehung.

z.B.

Klasse Rectangle {

/Konstruktorcode/

public void changeWidth() {....} public void changeLength() {....}

}

changeWidth und changeLength sind zwei Funktionen, die für ein Rechteck, aber nicht für ein Quadrat sinnvoll sind, da alle Seiten im Quadrat gleich sind. Obwohl Sie Ihre eigene Implementierung von beiden Funktionen in der quadratischen Klasse hacken und geben können, sieht noch aus meiner Sichtbeziehung nicht natürlich aus.

Wie für andere Antworten stimme ich ihnen zu.