Java tritt am Dienstag in Kraft! Mit Bedacht "Klon" abdecken

Heute sprechen wir über die klonbare Schnittstelle und die damit verbundenen Klonfunktionen. Um ehrlich zu sein, hatte ich in der Vergangenheit noch nie eine Interaktion mit dieser Methode, und nachdem ich diese Methode kennengelernt habe, bin ich mir nicht sicher, ob ich dies wirklich tun möchte, was fehleranfällig zu sein scheint. Lassen Sie uns diese Methode daher gründlich verstehen, damit wir eine fundierte Entscheidung darüber treffen können, ob wir diese Methode verwenden möchten.

Was ist das für eine klonbare Schnittstelle? Es ist eine Mixin-Schnittstelle, um Klassenbenutzer darüber zu informieren, dass sie bestimmte Operationen an der Klasse ausführen können. Das sehr seltsame an diesem speziellen Mixin ist, dass es keine bestimmte Funktion ausführen muss, sondern nur als Flag fungiert, sodass die Implementierungsklasse Methoden für die übergeordnete Klasse aufrufen kann. Dies bedeutet, dass Benutzer, die diese Klasse implementieren, möglicherweise nicht immer Methoden für die geklonte Klasse aufrufen, ohne auf Reflexion zurückzugreifen, und selbst dies funktioniert möglicherweise nicht. Davon abgesehen ist dies eine Objektklasse, daher ist es notwendig, sie zu verstehen und zu wissen, wie die Methode und alternative Methoden implementiert werden. Dieses Kapitel gilt für die Übernahme von Java.

Was ist Vertragsklonen? Wie oben erwähnt, enthält es keine Methoden, sondern dient als Methodenobjektklasse im Klon des Flags des geschützten Objekts. Wenn eine Klasse aufruft, um das Objekt zu klonen, um das Klonen zu implementieren, gibt der Objektklon eine feldweise Kopie des Objekts zurück. Wenn die Klasse nicht klonbar implementiert, wird eine CloneNotSupportedException ausgelöst. Wenn sich diese Verwendung einer Schnittstelle seltsam anfühlt, ist dies kein Verhalten, das Sie in Ihren eigenen Klassen nachahmen sollten. Der allgemeine (wenn auch schwache) Vertrag lautet as folgt:

  • Die Implementierungsklasse sollte einen öffentlichen Klon erstellen und die Methode super. Clone () aufrufen. (x.clone ()! = x) == true einfach, Clone sollte ein neues Objekt zurückgeben und nicht nur das aktuelle Objekt zurückgeben. (x.clone (). getClass () == x.getClass () == true this Keine absolute Anforderung, aber es kann erwartet werden. X. Clone.equals (x) == true Ebenso ist dies keine absolute Anforderung, aber es verringert die Überraschung, wie es funktioniert.

Jemand könnte denken, dass Sie das Aufrufen von super. Clone () Ihrer eigenen Methode clone method überspringen und dann einfach den Konstruktor aufrufen können, um ein neues Objekt zu erstellen. Dies kann jedoch dazu führen, dass die Klasse erweitert und super. Clone () aufgerufen wird, da die falsche Klasse zurückgegeben wird Objekte. Wie oben erwähnt, verstieß dies nicht gegen den Vertrag, sondern gegen die Vereinbarung.

Lassen Sie uns daher das Arbeitsprinzip und die Implementierungsmethode genauer untersuchen. Die Klonmethode wird durch Aufrufen von super.clone () implementiert, wodurch eine voll funktionsfähige Kopie der aufrufenden Klasse zurückgegeben wird. Wenn Ihre Klasse nur Grundelemente oder Verweise auf unveränderliche Objekte enthält, müssen Sie dies möglicherweise tun. Schauen wir uns ein Beispiel an:

@Override
public Address clone() {
  try {
    return (Address) super.clone();
  } catch (CloneNotSupportedException impossible) {
    // This will never happen.
    throw new AssertionException();
  }
}

Schauen wir uns einige interessante Dinge an. Da der Rückgabetyp der Objektklonmethode das Objekt ist, möchten wir ihn in den Typ unserer Klasse konvertieren. Dies ist gut, da Java kovariante Typen zulässt. Kurz gesagt, es ermöglicht uns, Unterklassen der gewünschten Klasse anstelle des übergeordneten Typs zu verwenden. Diese Umwandlung ist immer erfolgreich und ermöglicht es dem Client-Code, die Typumwandlung zu überspringen. Das nächste interessante ist zu versuchen zu fangen. Die Signatur der Objektmethode beinhaltet, dass eine CloneNotSupportedException ausgelöst wird. Wenn die Klasse eine klonbare Schnittstelle implementiert, die diese Ausnahme niemals auslöst, ist dies ein Beispiel für die schlechte Verwendung geprüfter Ausnahmen und sollte RuntimeException sein.

Schauen wir uns daher ein Beispiel an, in dem die Klasse mit nicht primitiven Feldern etwas komplizierter ist.

public class Stack {
  private Object[] elements;
  private int size;
  private static final int DEFAULT_INITIAL_SIZE = 16;

  public Stack() {
    elements = new Object[DEFAULT_INITIAL_SIZE];
  }

  public void push(Object o) {
    ensureCapacity();
    elements[size++] = o
  }

  public Object pop() {
    if (size == 0) {
      throw new StackEmptyException();
    }

    Object result = elements[--size];
    elements[size] = null;
    return result;
  }

  private ensureCapacity() {
    if (elements.length == size) {
      elements = Arrays.copyOf(elements, 2 * size + 1);
    }
  }
}

Was ist, wenn wir dieses Heap-Klassen-Tool klonbar machen und versuchen möchten, unsere Adressklasse zu imitieren? Wir werden am Ende ein Array von Feldern mit Replikatgröße haben, aber das Objekt wird von den beiden Instanzen gemeinsam genutzt. Dies wird viele Probleme verursachen, daher müssen wir noch weiter gehen. Stellen Sie sich die Klonmethode als eine der Konstruktionsmethoden vor, die das ursprüngliche Objekt schützen müssen. Schauen wir uns also eine mögliche Heap-Klasse für Klonmethoden an:

@Override
public class Stack clone() {
  try {
    // this gets us a replica with copied size field
    Stack copy = (Stack) super.clone();
    copy.elements = elements.clone();
    return copy;
  } catch (CloneNotSupportedException impossible) {
    throw new AssertionError();
  }
}

Jetzt klonen wir effektiv unsere Heap-Klasse. Unsere rekursive Call-Clone-Methode kann viele Probleme mit der Clone-Methode lösen, aber nicht alle. Es gibt Zeiten, in denen Sie dies weiterentwickeln und tiefe Kopien von Elementen erstellen müssen. Es gibt viele Möglichkeiten, dies zu erreichen, und wir werden es nicht tun Gehen Sie alle hier durch, aber es ist etwas, das Sie beachten sollten.

Andere Dinge zu beachten:

  • Da Klonmethoden Konstruktoren ähnlich sind, sollten sie keine wiederbeschreibbaren Methoden aufrufen. Selbst wenn die Klonmethode des Objekts eine CloneNotSupportedException auslöst, sollte Ihre Ersetzung dies nicht tun. Beim Entwerfen geerbter Klassen haben Sie zwei Möglichkeiten. Objekte, die dieselbe Methode zum Klonen von Signaturen implementieren, geben Implementierern die Freiheit zu wählen, ob das Klonen implementiert werden soll oder nicht. Eine andere Option besteht darin, das Klonen zu implementieren und CloneNotSupportedException zufällig auszulösen, wodurch das Klonen verhindert wird. Wenn Ihr Kurs threadsicher sein muss, denken Sie daran, dass die Klonimplementierung auch synchronisiert werden muss. Objektklonmethoden werden nicht synchronisiert.

Lohnt es sich also? Wahrscheinlich nicht. Es gibt viele einfache Wege, um dieses Ziel zu erreichen. Normalerweise kann der Kopierkonstruktor oder die Kopierfabrik die Arbeit direkter erledigen. In unserer Adressensituation könnte dies also so aussehen:

public class Address(Address originalAddress) { ... }

Oder

public static Address newInstance(Address originalAddress) { ... }

Welche Vorteile bietet die Verwendung einer dieser Methoden anstelle der Implementierung des Klonens:

  • Sie sind nicht auf das Kopierverhalten zwischen fehleranfälligen Feldern angewiesen. Sie müssen nicht nicht offensichtlichen und nicht aufgezeichneten Verträgen folgen. Kein Konflikt mit der Verwendung des letzten Feldes erfordert nicht, dass wir uns mit unnötigen Prüfausnahmen befassen. Sie ermöglichen die Verwendung von Parametern des Typs der von der Klasse implementierten Schnittstelle. Dies machen wir mit Sammlungen in der Standardbibliothek.

Kurz gesagt, Sie sollten wahrscheinlich keine klonbare Schnittstelle implementieren. Stattdessen müssen wir eines der anderen Muster erreichen, z. B. den Kopierkonstruktor oder die Kopierfabrik. Mit diesen Methoden sollten Sie eine bessere Erfahrung machen und die falsche Codebasis reduzieren.

von: https://dev.to//kylec32/effective-java-tuesday-override-clone-judiciously-4fg

Veröffentlicht 0 Originalartikel · Gefällt mir 0 · Besuche 654

Ich denke du magst

Origin blog.csdn.net/cunxiedian8614/article/details/105691106
Empfohlen
Rangfolge