10
votes

Java: CLONE Collection arbitraire en référence à la collecte

Supposons que vous ayez une référence de type java.util.collection dans une méthode et ne peut pas dire quelle implémentation de java.util.collection sera-t-il pointant à l'exécution temps, est-il possible de cloner la collection?

Je voulais mettre en œuvre une méthode générique qui filtrera tout type de collecte donnée. Par conséquent, la méthode prendra java.util.collection comme entrée. Cependant, au-delà de cela, je ne voulais pas modifier la collection d'origine, alors je voulais cloner la collection.


3 commentaires

Pourquoi avez-vous besoin de votre collection de sortie pour être le même type que l'entrée?


La collection d'origine devrait-elle rester non modifiée?


@Nicolas: matière de commodité :)


7 Réponses :


0
votes

En théorie, il est possible de réflexion, mais pas tous les la collection peuvent (ou doivent) être instanciés de cette façon. Un premier exemple est le résultat de collections.singletonlist () , qui n'a pas de constructeurs publics du tout. D'autres collections spéciales peuvent également soulever d'autres problèmes.

Ce que je ferais à la place, c'est simplement vérifier les interfaces de la collection d'entrée et renvoyer une implémentation "par défaut" pour ce type. Donc, par exemple: xxx

ans ainsi de suite.


1 commentaires

Demain, tout le monde peut implémenter la collection.



0
votes

Si la collection implémente clonable , vous pouvez le faire. Vous n'auriez pas à vous soucier du type exact; Clone de la collection () La mise en œuvre prendrait en charge cela.


4 commentaires

Objet.clone () est protégé. Vous ne pouvez pas simplement l'appeler si vous ne connaissez pas le type réel de l'objet. Eh bien, vous pouvez peut-être le faire en utilisant la réflexion comme Biziclop suggéré dans sa réponse.


Correction de ce problème - oublié que vous avez besoin de mettre en œuvre clonable et de remplacement clone () .


Même si vous implémentez clonable , la méthode du clone peut ne pas être publique, voir le Javadoc download.oracle.com/javase/6/docs/aplon/java/lang/cloneable.ht ml


Oui, voir la réponse de @ Ralph pour la solution à cela. (Je pense)



2
votes

Je vois trois options:

  1. s'appuyer sur la méthode de la collection CLONE (en supposant que cela implémente clonable ) puis retirez les éléments indésirables. Edit: comme indiqué dans les commentaires et autres réponses, Clone () n'est pas public et n'est donc pas accessible.

  2. Demandez à l'appelant de fournir une collection vide pour copier les éléments cibles entre la source et la destination.

  3. Définissez une interface d'usine pour créer une collection vide et demander à l'appelant de fournir une implémentation d'usine. Ensuite, copiez les éléments cibles entre la source et la destination.


1 commentaires

Consultez mon commentaire sur Michael Post sur la méthode du clone et l'interface CloneBL.



9
votes

Malheureusement, la collection d'interface ne dit rien sur la mise en œuvre d'une interface clignaire.


mais ce que vous pouvez toujours faire est de copier la collection: p> xxx pré>

Si vous voulez seulement vous assurer qu'il n'est pas modifié, enveloppez-la avec une collection non modifiable au lieu de le cloner: P>

Collection<T> unmodifiable = Collections.unmodifiableCollection(original);


4 commentaires

Fortez quelques-unes des implémentations de Collection DO, SO L'instanceOf fonctionnerait pour de nombreux cas.


Regardez le commentaire sur d'autres réponses: Clonable ne signifie pas que vous pouvez utiliser la méthode du clone.


La référence à la collection non modifiable restera locale, la collection d'origine est toujours modifiable par des références à l'extérieur, je voulais modifier une copie de la collection d'origine et le renvoyer.


@Nicloas: ma faute - j'ai enlevé cette partie de la réponse



4
votes

Je vais démontrer à Scala, car il a une replace où je peux tester, mais la même sémantique devrait travailler dans Java. XXX

Le Scala Replucle me dit que TheClone a type statique type objet (vous pouvez lancer ceci sur collection [int] ou linkedlist [int] ), mais le type dynamique du clone est toujours LinkedList .

MAINTENANT, je suppose que ce que vous voulez est une méthode qui renvoie un type statique linkedlist quand il reçoit un type statique LinkedList et renvoie un type statique ArrayList Lorsqu'il reçoit un type statique ArrayList , etc., auquel cas xxx

En Java, je pense que c'est xxx


0 commentaires

1
votes

Mieux vaut filtrer la collection en la modifiant dans votre méthode. Jusqu'à l'appelant pour vous fournir la collection d'origine ou une copie appropriée de celle-ci.


0 commentaires

3
votes

Si vous vraiment, vraiment, vraiment, vraiment besoin de le faire, il y a un piratage laid.

  public static <T> T tryToClone(T object)
      throws CloneNotSupportedException {
    Object clone = null;

    // Use reflection, because there is no other way
    try {
      Method method = object.getClass().getMethod("clone");
      clone = method.invoke(object);
    } catch (InvocationTargetException e) {
      rethrow(e.getCause());
    } catch (Exception cause) {
      rethrow(cause);
    }
    if (object.getClass().isInstance(clone)) {
      @SuppressWarnings("unchecked") // clone class <= object class <= T
      T t = (T) clone;
      return t;
    } else {
      throw new ClassCastException(clone.getClass().getName());
    }
  }

  private static void rethrow(Throwable cause)
      throws CloneNotSupportedException {
    if (cause instanceof RuntimeException) {
      throw (RuntimeException) cause;
    }
    if (cause instanceof Error) {
      throw (Error) cause;
    }
    if (cause instanceof CloneNotSupportedException) {
      throw (CloneNotSupportedException) cause;
    }
    CloneNotSupportedException e = new CloneNotSupportedException();
    e.initCause(cause);
    throw e;
  }


1 commentaires

FYI, cela vient d'ici: code.google.com/p/google-Collections/source/trunt/trunk/src / ... - Nous l'avons ensuite supprimé, car c'est un terrible no -Good inutile sale hacky hacky hacky.