Daniel Thoma: URL "normalisieren"

Beitrag lesen

Hallo Bernhard,

Kompatibilitätsgründe verhindern eigentlich nicht, dass man die Vererbungshierarchie in dieser Weise ändert. Auf Code der URL benutzt, hätte das ja keine Auswirkungen.
Bist du da sicher?

Naja, fast ;-) Bei Serialisierung bin ich mir nicht sicher, da würde es wohl knallen. Das würde es allerdings auch bei jedem zusätzlichen neuen Feld o.ä.  jedenfalls, wenn man nicht zusätzlich Code für die Deserialisierung von altem Kram schreibt.

Ich denke mir folgendes: Fügt man URI als Oberklasse für URL hinzu, würde sich garantiert die Größe (im Sinne von Speicherbedarf) eines URL-Objektes ändern.

Die Größe eines Objektes ist nicht garantiert. Du hast auch keine Chance herauszufinden, wie viel Speicherplatz ein Objekt wirklich belegt und wie es im Speicher abgelegt ist. Bei anderen Sprachen könnte das vielleicht ein Problem sein, bei Java aber nicht.

Wenn man ein Java-Programm hat, welches noch mit einer älteren Java-Version, die URI als Oberklasse _nicht_ kennt, kompiliert wurde, und dieses einem neueren Interpreter verfüttert, kommt der dann zur Laufzeit einfach so mit den alten URL-Objekten zurecht?

Ja das sollte es. Da steht ja nur drin, welche Klasse geladen werden soll (java.net.URL in dem Fall). Die VM wird die neue Klasse laden und so lang die Schnittstelle kompatibel ist, wird da nichts passieren.

Das sollte man bei Vererbung vermeiden, da Code der eine URI verwendet, sich ja nicht nur darauf verlässt, dass es die gleichen Methoden hat, sondern auch darauf, dass die das gleiche oder etwas sehr ähnliches tun.
Den letzten Satz halte ich für falsch. Der Sinn der objektorientierten Programmierung ist ja gerade Polymorphismus, also die Möglichkeit, Unterklassen zu bilden und Methoden zu überschreiben und dass die jeweils zum konkreten Objekt passende zur Laufzeit aufgerufen wird ("dynamic binding"), auch wenn nur der Typ der Oberklasse bekannt ist. Dass diese Methode alles mögliche machen kann, sollte jeder OO-Programmierer wissen.

Vielleicht hätte ich es genauer ausdrücken sollen. Natürlich darf eine erweiternde Klasse etwas anderes tun, das ist ja der Sinn. Allerdings haben Methoden neben ihrer Signatur in der Regel eine Spezifikation, die beschreibt, was sie tut. toString() gibt z.B. eine String-Darstellung eines Objektes zurück. Es wäre falsch, ihn ihrer Implementierung System.exit(0); aufzurufen. Natürlich kann man das tun und kein Compiler verhindert das, aber es verletzt die Vereinbarungen, die in der Dokumentation stehen bzw. von der Beschreibung dort her erwartet werden.
Viele andere Methoden haben noch viel genauere, auch explizit aufgeschriebene Spezifikationen.
Ein schönes, praktisches Beispiel sind hashCode() und equals(Object). Die werden öfter mal nicht ganz korrekt implementiert, was dann zu absolut unnachvollziehbarem Verhalten von HashSets u.ä. führt.

Bei URI kann man nun z.B. relative Pfade setzen oder auch nicht normalisierte. Wenn nun eine Klasse stattdessen RuntimeExceptions wirft, solche aufrufe ignoriert, oder sonst irgend etwas macht, wird Code, der sich darauf verlässt, nicht mehr funktionieren. Und man muss sich auf solche Vereinbarungen verlassen, sonst würde man ja nur noch hypothetische Ausnahmesituationen berücksichtigen.

Grüße

Daniel