{"id":1412,"date":"2012-07-02T16:41:07","date_gmt":"2012-07-02T14:41:07","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=1412"},"modified":"2012-07-02T16:41:22","modified_gmt":"2012-07-02T14:41:22","slug":"nderungen-an-schnittstellen-code-kompatibilitt-und-binr-kompatibilitt","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2012\/07\/nderungen-an-schnittstellen-code-kompatibilitt-und-binr-kompatibilitt\/","title":{"rendered":"&Auml;nderungen an Schnittstellen: Code-Kompatibilit&auml;t und Bin&auml;r-Kompatibilit&auml;t"},"content":{"rendered":"<p>Sind Schnittstellen einmal deklariert und in einer gro\u00dfen Anwendung verbreitet, so sind \u00c4nderungen nur schwer m\u00f6glich, da sie schnell die Kompatibilit\u00e4t brechen. Wird der Name einer Parametervariablen umbenannt, ist das kein Problem, aber bekommt eine Schnittstelle eine neue Operation, f\u00fchrt das zu einem \u00dcbersetzungsfehler, wenn nicht automatisch alle implementierenden Klassen diese neue Methode implementieren. Framework-Entwickler m\u00fcssen also sehr drauf achten, wie sie Schnittstellen modifizieren, doch sie haben es in der Hand, wie weit die Kompatibilit\u00e4t gebrochen wird.<\/p>\n<p>Geschichtsstunde<\/p>\n<p>Schnittstellen sp\u00e4ter zu \u00e4ndern, wenn schon viele Klassen die Schnittstelle implementieren, ist eine schlechte Idee. Denn erneuert sich die Schnittstelle, etwa wenn nur eine Operation hinzukommt oder sich ein Parametertyp \u00e4ndert, dann sind pl\u00f6tzlich alle implementierenden Klassen kaputt. Sun selbst hat dies bei der Schnittstelle java.sql.Connection riskiert. Beim \u00dcbergang von Java 5 auf Java 6 wurde die Schnittstelle erweitert, und keine Treiberimplementierungen konnten mehr compiliert werden.<\/p>\n<p><strong>Code-Kompatibilit\u00e4t und Bin\u00e4r-Kompatibilit\u00e4t<\/strong><\/p>\n<p>Es gibt \u00c4nderungen, die f\u00fchren zwar zu Compilerfehlern, wie neu eingef\u00fchrten Operationen, sind aber zur Laufzeit in Ordnung. Bekommt eine Schnittstelle eine neue Methode, so ist das f\u00fcr die JVM \u00fcberhaupt kein Problem. Die Laufzeitumgebung arbeitet auf den Klassendateien selbst und sie interessiert es nicht, ob eine Klasse brav alle Methoden der Schnittstelle implementiert; sie l\u00f6st nur Methodenverweise auf. Wenn eine Schnittstelle pl\u00f6tzlich \u201emehr\u201c vorschreibt, hat sie damit kein Problem.<\/p>\n<p>W\u00e4hrend also fast alle \u00c4nderungen an Schnittstellten zum Bruch der Codebasis f\u00fchren, sind doch einige \u00c4nderungen f\u00fcr die JVM in Ordnung. Wir nennen das Bin\u00e4r-Kompatibilit\u00e4t. Zu den bin\u00e4r-kompatiblen \u00c4nderungen z\u00e4hlen:<\/p>\n<li>Neue Methode hinzuf\u00fcgen<\/li>\n<li>Schnittstelle erbt von einer zus\u00e4tzlichen Schnittstelle<\/li>\n<li>Hinzuf\u00fcgen\/L\u00f6schen einer throws-Ausnahme<\/li>\n<li>Letzten Parametertyp von T[] in T&#8230; \u00e4ndern<\/li>\n<li>Neue Konstanten, also statische Variablen hinzuf\u00fcgen<\/li>\n<p>Die Anzahl der bin\u00e4r-inkompatiblen \u00c4nderungen sind jedoch gradierender. Verboten sind:<\/p>\n<li>\u00c4ndern des Methodennamens<\/li>\n<li>\u00c4ndern der Parametertypen und Umsortieren der Parameter<\/li>\n<li>Formalen Parameter hinzunehmen oder entfernen<\/li>\n<p><strong>Strategien zum \u00c4ndern von Schnittstellen<\/strong><\/p>\n<p>Falls die Schnittstelle nicht gro\u00df ver\u00f6ffentlicht wurde, so lassen sich einfacher \u00c4nderungen vornehmen. Ist der Name einer Operation zum Beispiel schlecht gew\u00e4hlt, wird ein Refactoring in der IDE den Namen in der Schnittstelle genauso \u00e4ndern wie auch alle Bezeichner in den implementierenden Klassen. Problematischer ist es, wenn externe Nutzer sich auf die Schnittstelle verlassen. Eine L\u00f6sung ist, diese Klienten ebenfalls zur \u00c4nderung zu zwingen, oder auf \u201eSch\u00f6nheits\u00e4nderungen\u201c, wie dem \u00c4ndern des Methodenamens, einfach zu zu verzichten.<\/p>\n<p>Kommen Operationen hinzu, hat sich eine Konvention etabliert, die im Java-Universum oft anzutreffen ist: Soll eine Schnittstelle um Operationen erweitert werden, so gibt es eine neue Schnittstelle, die die alte erweitert, und auf \u201e2\u201c endet; java.awt.LayoutManager2 ist so ein Beispiel aus dem Bereich der grafischen Oberfl\u00e4chen, Attributes2, EntityResolver2, Locator2 f\u00fcr XML-Verarbeitung sind weitere. Ein Blick auf die API vom Eclipse-Framework (<a href=\"http:\/\/help.eclipse.org\/juno\/topic\/org.eclipse.platform.doc.isv\/reference\/api\/index.html?overview-summary.html\">http:\/\/help.eclipse.org\/juno\/topic\/org.eclipse.platform.doc.isv\/reference\/api\/index.html?overview-summary.html<\/a>) zeigt, dass bei mehr als 3500 Typen dieses Muster um die 70 Mal angewendet wurde.<\/p>\n<p>Seit Java 8 gibt es eine weitere M\u00f6glichkeit Operationen in Schnittstellen hinzuzuf\u00fcgen, sogenannte Virtuelle Erweiterungsmethoden. Sie erweitern die Schnittstelle, f\u00fcgen aber gleich schon eine vorgefertigte Implementierung mit, sodass Unterklassen nicht zwingend eine Implementierung anbieten m\u00fcssen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sind Schnittstellen einmal deklariert und in einer gro\u00dfen Anwendung verbreitet, so sind \u00c4nderungen nur schwer m\u00f6glich, da sie schnell die Kompatibilit\u00e4t brechen. Wird der Name einer Parametervariablen umbenannt, ist das kein Problem, aber bekommt eine Schnittstelle eine neue Operation, f\u00fchrt das zu einem \u00dcbersetzungsfehler, wenn nicht automatisch alle implementierenden Klassen diese neue Methode implementieren. Framework-Entwickler [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11],"tags":[],"class_list":["post-1412","post","type-post","status-publish","format-standard","hentry","category-insel"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1412","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=1412"}],"version-history":[{"count":2,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1412\/revisions"}],"predecessor-version":[{"id":1414,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1412\/revisions\/1414"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=1412"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=1412"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=1412"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}