Was ist Binärkompatibilität in Java?

Lesezeit: 6 Minuten

Sams Benutzeravatar
Sam

Ich habe „Effective Java“ von Joshua Bloch gelesen.

In Punkt 17: „Interfaces nur zum Definieren von Typen verwenden“ bin ich auf die Erklärung gestoßen, wo es nicht ratsam ist, Interfaces zum Speichern von Konstanten zu verwenden. Die Erklärung füge ich unten ein.

„Schlimmer noch, es stellt eine Verpflichtung dar: Wenn die Klasse in einer zukünftigen Version so geändert wird, dass sie die Konstanten nicht mehr verwenden muss, muss sie dennoch die Schnittstelle implementieren, um die Binärkompatibilität sicherzustellen.“

Was bedeutet hier Binärkompatibilität?

Kann mich jemand mit einem Beispiel in Java anleiten, um zu zeigen, dass Code binärkompatibel ist.

Benutzeravatar von Evgeniy Dorofeev
Evgeniy Dorofeev

Kurz gesagt, binäre Kompatibilität bedeutet, dass Sie Klassen, die sie verwenden, nicht neu kompilieren müssen, wenn Sie Ihre Klasse ändern. Beispielsweise haben Sie eine öffentliche oder geschützte Methode aus dieser Klasse entfernt oder umbenannt

public class Logger implements Constants {
   public Logger getLogger(String name) {
         return LogManager.getLogger(name);
   }
}

aus Ihrer log-1.jar-Bibliothek und veröffentlichte eine neue Version als log-2.jar. Wenn Benutzer Ihrer log-1.jar die neue Version herunterladen, werden ihre Apps beschädigt, wenn sie versuchen, die fehlende getLogger(String name)-Methode zu verwenden.

Und wenn Sie die Constants-Schnittstelle (Punkt 17) entfernen, wird dies aus demselben Grund auch die Binärkompatibilität beeinträchtigen.

Sie können jedoch ein privates oder privates Paketelement dieser Klasse entfernen / umbenennen, ohne die Binärkompatibilität zu beeinträchtigen, da externe Apps es nicht verwenden können (oder sollten).

  • Was mich erstaunt, ist, dass die offiziellen Dokumentationen ihre Sachen nicht mit dieser Einfachheit erklären können. Ich bin mir nicht sicher, warum sie eine ähnliche Sprache verwenden wollen, die Anwälte normalerweise in Begriffen und Vereinbarungen verwenden.

    – Tarik

    23. April 2014 um 1:19 Uhr

  • Richard E. Little hat ein sehr einfaches, schönes Beispiel auf seinem bloggen. Es ist Wirklich zeigt eher das Problem der Binärkompatibilität als das der Quellcodekompatibilität, wie in dieser Antwort (mit der umbenannten Methode) veranschaulicht.

    – Yann-Gaël Guéhéneuc

    9. Mai 2014 um 6:43 Uhr

  • @Tarik, welche offizielle Dokumentation hast du versucht, dass du eine so mutige Aussage machen kannst?

    – Holger

    1. Februar 2022 um 11:42 Uhr

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

Um das Konzept besser zu verstehen, ist es interessant zu sehen, dass Binärkompatibilität NICHT API-Kompatibilität impliziert, noch umgekehrt.

API-kompatibel, aber NICHT binärkompatibel: statische Entfernung

Version 1 der Bibliothek:

public class Lib {
    public static final int i = 1;
}

Kundencode:

public class Main {
    public static void main(String[] args) {
        if ((new Lib()).i != 1) throw null;
    }
}

Client-Code mit Version 1 kompilieren:

javac Main.java

Version 1 durch Version 2 ersetzen: entfernen static:

public class Lib {
    public final int i = 1;
}

Neu kompilieren Nur Version 2, nicht den Client-Code und führen Sie ihn aus java Main:

javac Lib.java
java Main

Wir bekommen:

Exception in thread "main" java.lang.IncompatibleClassChangeError: Expected static field Lib.i
        at Main.main(Main.java:3)

Dies geschieht, weil, obwohl wir schreiben können (new Lib()).i in Java für beide static und Member-Methoden kompiliert es je nach in zwei verschiedene VM-Anweisungen Lib: getstatic oder getfield. Diese Pause wird bei erwähnt JLS7 13.4.10:

Wenn ein nicht als privat deklariertes Feld nicht als statisch deklariert wurde und als statisch deklariert wird oder umgekehrt, wird ein Verknüpfungsfehler, insbesondere ein IncompatibleClassChangeError, resultieren, wenn das Feld von einer bereits vorhandenen Binärdatei verwendet wird, die ein Feld erwartet der anderen Art.

Wir müssten neu kompilieren Main mit javac Main.java damit es mit der neuen Version funktioniert.

Anmerkungen:

  • Aufruf statischer Member von Klasseninstanzen wie (new Lib()).i ist schlechter Stil, warnt und sollte niemals getan werden
  • Dieses Beispiel ist konstruiert, weil es nicht statisch ist final Primitive sind nutzlos: immer verwenden static final für Primitive: privates abschließendes statisches Attribut vs. privates abschließendes Attribut
  • Reflexion könnte verwendet werden, um den Unterschied zu sehen. Aber die Reflexion kann auch private Felder sehen, was offensichtlich zu Pausen führt, die nicht als Pausen zählen sollten, also nicht zählen.

Binärkompatibel, aber NICHT API-kompatibel: Null-Vorbedingungsverstärkung

Version 1:

public class Lib {
    /** o can be null */
    public static void method(Object o) {
        if (o != null) o.hashCode();
    }
}

Version 2:

public class Lib {
    /** o cannot be null */
    public static void method(Object o) {
        o.hashCode();
    }
}

Klient:

public class Main {
    public static void main(String[] args) {
        Lib.method(null);
    }
}

Dieses Mal, auch wenn neu kompilieren Main nach Aktualisierung Libwird der zweite Aufruf ausgelöst, aber nicht der erste.

Dies liegt daran, dass wir den Vertrag von geändert haben method auf eine Weise, die zur Kompilierzeit von Java nicht überprüfbar ist: bevor es dauern könnte nulldanach nicht mehr.

Anmerkungen:

  • Das Eclipse-Wiki ist eine großartige Quelle dafür: https://wiki.eclipse.org/Evolving_Java-based_APIs
  • APIs erstellen, die akzeptieren null Werte ist eine fragwürdige Praxis
  • Es ist viel einfacher, eine Änderung vorzunehmen, die die API-Kompatibilität unterbricht, aber nicht binär, als umgekehrt, da es einfach ist, die interne Logik von Methoden zu ändern

Beispiel für C-Binärkompatibilität

Was ist eine Application Binary Interface (ABI)?

  • IMHO ist das erste Beispiel falsch, weil Sie entfernen static und es ist jetzt API-Inkompatibilität (dh. Lib.i in Bytecode funktioniert nicht mehr). Um die API-Kompatibilität für einen bestimmten Code zu begründen, hängt es nicht davon ab, ob Clients diese API verwenden, sondern vom Standard (oder der Spezifikation) für die API-Kompatibilität. Obwohl ich damit einverstanden bin, bedeutet API-Kompatibilität keine Binärkompatibilität.

    – schwimmende Katze

    28. Februar 2016 um 14:11 Uhr

Wenn wir in Zukunft die Schnittstelle ändern möchten, die einige Klassen implementieren (z. B. Hinzufügen einiger neuer Methoden).

Wenn wir abstrakte Methoden hinzufügen (zusätzliche Methoden), dann die Klassen (Implementierung der Schnittstelle) muss implementieren die zusätzliche Methode, die eine Abhängigkeitsbeschränkung und einen Mehraufwand für die Durchführung derselben erzeugt.

Um dies zu überwinden, können wir hinzufügen Standard Methoden in der Schnittstelle.

Dadurch wird die Abhängigkeit zum Implementieren der zusätzlichen Methoden entfernt.

Wir müssen die implementierende Klasse nicht modifizieren, um Änderungen aufzunehmen. Dies wird als Binärkompatibilität bezeichnet.

Bitte beziehen Sie sich auf das folgende Beispiel:

Die Schnittstelle, die wir verwenden werden

    //Interface       
    interface SampleInterface
            {
                // abstract method
                public void abstractMethod(int side);

                // default method
                default void defaultMethod() {
                   System.out.println("Default Method Block");
                }

                // static method
                static void staticMethod() {
                    System.out.println("Static Method Block");
                }
            }


//The Class that implements the above interface.

    class SampleClass implements SampleInterface
    {
        /* implementation of abstractMethod abstract method, if not implemented 
        will throw compiler error. */
        public void abstractMethod(int side)
        {System.out.println(side*side);}

        public static void main(String args[])
        {
            SampleClass sc = new SampleClass();
            sc.abstractMethod(4);

            // default method executed
            sc.defaultMethod();

            // Static method executed
            SampleInterface.staticMethod();

        }
    }

Notiz: Nähere Informationen finden Sie unter Standardmethoden

  • Standard- und statische Methoden sind in Java Version 8 oder höher verfügbar.

    – BIPIN SHARMA

    18. Oktober 2017 um 7:19 Uhr

1444360cookie-checkWas ist Binärkompatibilität in Java?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy