Verständnis dieser Warnung: Die serialisierbare Klasse erklärt keine statische endgültige Serialversionuid

StackOverflow https://stackoverflow.com/questions/1514881

Frage

Ich habe einen statischen Initialisierercode:

someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
  put("a","value-a"); 
  put("c","value-c");}
});

Aus irgendeinem Grund bekomme ich eine Warnung vor Eclipse: Die serialisierbare Klasse erklärt keine statische endgültige Serialversionuid.

Beschwert sich das über die anonyme Klasse? Was kann ich dagegen tun oder sollte ich es einfach unterdrücken?

War es hilfreich?

Lösung

Die Syntax, die Sie verwenden, heißt Doppel-Brace-Initialisierung - was eigentlich ein "ist"Instanzinitialisierungsblock Das ist Teil eines Anonyme innere Klasse"(Sicherlich kein Hack). Wenn Sie diese Notation verwenden, definieren Sie tatsächlich eine neue Klasse (!).

Das "Problem" in Ihrem Fall ist das HashMap Geräte Serializable. Diese Schnittstelle hat keine Methoden und dient nur, um die Semantik des serialisierbaren Semantiks zu identifizieren. Mit anderen Worten, es ist eine Markierungsschnittstelle und Sie müssen konkret nichts implementieren. Aber, Während der Deserialisierung verwendet Java eine Versionsnummer namens a serialVersionUID Um zu überprüfen, ob die serialisierte Version mit dem Ziel kompatibel ist. Wenn Sie dies nicht zur Verfügung stellen serialVersionUID, es wird berechnet. Und wie im Javadoc von dokumentiert Serializable, Der berechnete Wert ist äußerst empfindlich und wird daher empfohlen, ihn explizit zu deklarieren, um Deserialisierungsprobleme zu vermeiden. Und das ist es, was Eclipse "beschwert" (beachten Sie, dass dies nur eine Warnung ist).

Um diese Warnung zu vermeiden, können Sie a hinzufügen serialVersionUID zu Ihrer anonymen inneren Klasse:

someMethodThatTakesAHashMap(new HashMap<String, String>() {
    private static final long serialVersionUID = -1113582265865921787L;

    {
        put("a", "value-a");
        put("c", "value-c");
    }
});

Aber Sie verlieren die Übersicht über die Syntax (und Sie brauchen sie möglicherweise nicht einmal).

Eine andere Option wäre daher, die Warnung durch Hinzufügen a zu ignorieren @SuppressWarnings("serial") zu der Methode, bei der Sie anrufen someMethodThatTakesAHashMap(Map). Dies scheint in Ihrem Fall angemessener zu sein.

Das alles alles gesagt, obwohl diese Syntax prägnant ist, hat sie einige Nachteile. Wenn Sie zunächst eine Referenz auf das Objekt haben, die mit einer Doppel-Brace-Initialisierung initialisiert wurden, haben Sie implizit einen Verweis auf das äußere Objekt, das nicht für die Müllsammlung in Frage kommt. Also sei vorsichtig. Zweitens (dies klingt nach der Mikrooptimierung), hat die Doppel-Brace-Initialisierung a Sehr ein bisschen Overhead. Drittens verwendet diese Technik tatsächlich anonyme innere Klassen, wie wir es gesehen haben, und isst daher ein bisschen Permgen -Raum (aber ich bezweifle, dass dies wirklich ein Problem ist, es sei denn, Sie Ja wirklich sie missbrauchen). Schließlich - und dies ist vielleicht der wichtigste Punkt - ich bin mir nicht sicher, ob der Code lesbarer wird (er ist keine bekannte Syntax).

Während ich es in Tests (für die Übersicht) gerne verwende, vermeide ich es in der Regel in "regulärem" Code.

Andere Tipps

Ja, Sie könnten die Warnung unterdrücken, aber ich würde sie so umschreiben:

HashMap<String, String> map  = new HashMap<String, String>();
map.put("a","value-a"); 
map.put("c","value-c");
someMethodThatTakesAHashMap(map);

Keine Unterdrückung erforderlich und viel besser zu lesen, IMO.

Ich stimme Bart K. im Allgemeinen zu, aber zu informativen Zwecken:
Die Warnung kann auch durch Hinzufügen des Feldes beseitigt werden, das automatisch durch Treffer von Strg+1 generiert werden kann.
Die Warnung kann auch durch Hinzufügen der Annotation @Suppresswarnings ("Serial") vor der Definition unterdrückt werden.
Die anonyme Klasse implementiert serialisierbar, und serialisierbar erfordert dieses statische Feld, damit Versionen beim Serialisieren und Deserialisieren unterschieden werden können. Weitere Informationen hier:
http://www.javablogging.com/what-is-serialversionuid/

Das ImmutableMap Die Klasse aus der Google Collections -Bibliothek ist für diese Situation nützlich. z.B

someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());

oder

someMethodThatTakesAHashMap(ImmutableMap.of("a","value-a","c","value-c"));

Um die andere Hälfte Ihrer Frage zu beantworten: "Soll ich sie unterdrücken?" -

Ja. Meiner Meinung nach ist dies eine schreckliche Warnung. serialversionuid sollte standardmäßig standardmäßig nicht verwendet werden, nicht umgekehrt.

Wenn Sie keine Serialversionuid hinzufügen, ist das Schlimmste, dass zwei Versionen eines Objekts, die tatsächlich serialisierungsverbindlich sind, als nicht kompatibel angesehen werden. Serialversionuid ist ein Weg zu erklären, dass sich die Serialisierungskompatibilität nicht geändert hat und die Standardbewertung von Java überschrieben hat.

Mit serialversionuid ist das Schlimmste, was passiert, dass Sie die ID versehentlich nicht aktualisieren, wenn sich die serialisierte Form der Klasse inkompatible ändert. Bestenfalls erhalten Sie auch einen Laufzeitfehler. Im schlimmsten Fall passiert etwas Schlimmeres. Und stellen Sie sich vor, wie einfach es ist, es nicht zu aktualisieren.

Ihre Absicht war es, eine anonyme Instanz von HashMap zu initialisieren. Die Warnung ist Hinweis, dass Ihr Code mehr tut als Sie beabsichtigt haben.

Was wir suchen, ist eine Möglichkeit, eine anonyme HashMap -Instanz zu initialisieren. Was wir oben haben, erstellt eine anonyme Unterklasse von HashMap dann eine anonyme Instanz dieser anonymen Klasse.

Da der Code mehr als beabsichtigt ist, würde ich ihn als Hack nennen.

Was wir wirklich wollen, ist so etwas:

foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));

Aber leider ist das nicht gültig, Java. Es gibt keine Möglichkeit, etwas so auf Typ mit einer Reihe von Schlüssel-/Wertpaaren zu tun. Java Simple hat nicht die ausdrucksstarke Kraft.

Die statischen Methoden der Google Collection immutablemap.of sind jedoch in der Nähe, aber sie bedeutet, eine Version der Werksmethode für verschiedene Zahlen von Schlüssel-/Wertpaaren zu erstellen. (Siehe Finnws Antwort.)

Also halte die Dinge einfach. Gehen Sie mit der Lösung von Bart K, es sei denn, Ihr Code ist mit dieser Initialisierung übersät. Wenn ja, verwenden Sie Immutablemap. Oder rollen Sie Ihre eigene Hashmap -Unterklasse mit den "von" Style Factory -Methoden. Oder erstellen Sie diese "von" Style Factory -Methoden in einer Versorgungsklasse. Hier ist einer für zwei Schlüssel-/Wertpaare:

public final MapUtil {
    public static <K,V> Map<K,V> makeMap(K k1, V v1, K k2, V v2) {
        Map<K,V> m = new HashMap<K,V>();
        m.put(k1, v1);
        m.put(k2, v2);
        return m;
    }
}

Nehmen Sie die Ausführlichkeit an und trösten Sie im Wissen, dass Ihre Unternehmenskollegen die gleichen Fesseln wie Sie tragen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top