Question

Si une classe Java implémente l'interface Serializable mais ne dispose pas d'une méthode de clone() public, il est généralement possible de créer une copie en profondeur comme ceci:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

Je rencontre souvent des cours de bibliothèque tiers comme celui-ci et le recours aux hacks comme celle-ci. J'ai même ObjectOutputStream étendu à l'occasion de faire la copie moins profonde. Il n'a jamais causé de graves problèmes, autre que d'être inefficace (lent à encoder / décoder et les graphiques de sérialisation temporaires peuvent consommer beaucoup de mémoire.)

Et si ce n'est pas sûr d'utiliser cette technique, la classe ne devrait probablement pas avoir été déclarée Serializable.

Alors, ce que je voudrais savoir est, si votre classe est Serializable, ce qui pourrait vous empêcher de définir une méthode de clone() publique (en utilisant l'interface Cloneable ou un constructeur de copie?)


Related: Copier un objet en Java

Était-ce utile?

La solution

Eh bien, vous dites le mécanisme de sérialisation est une façon de « clone » objets indirectement. C'est bien sûr pas sa fonction première. Il est généralement utilisé pour laisser des programmes transmettre des objets à travers un réseau, ou de stocker puis de les lire. Vous pouvez vous attendre un objet à utiliser de cette façon, et mettre en œuvre Serializable, sans attendre code pour cloner des objets localement, et non mettre en œuvre Cloneable.

Le fait que le code fonctionne autour de cette via sérialisation suggère le code utilise un objet d'une manière que l'auteur n'a pas l'intention, ce qui pourrait être l'auteur ou l'appelant de la « faute », mais cela ne signifie pas que Serializable général et Cloneable vont ensemble.

Par ailleurs, je ne suis pas sûr clone () est « cassé » autant que difficile à mettre en œuvre correctement. Un constructeur de copie est plus naturel à utiliser et obtenir le droit à mon humble avis.

Autres conseils

Je préférerais utiliser un constructeur de copie plutôt que d'utiliser le mécanisme ci-dessus. Vous pouvez définir plus finement ce qui est d'être profondément ou copié peu profondément, et faire le copier d'un objet distinct du sérialisation d'un objet. Un constructeur de copie peut (par exemple) permet de partager deux objets une référence à un objet maître, alors que cela peut ne pas être approprié pour un objet sérialisé et transmis à travers le réseau.

Notez que la méthode de Cloneable est largement considéré aujourd'hui comme rompu. Voir cet article avec Joshua Bloch pour plus d'informations. En particulier, il ne dispose pas d'une méthode clone()!

Du point de Brian à propos Cloneable est très bon, mais même si Cloneable a travaillé à droite, il y a encore des cas où vous voudrez peut-être un objet à serializeable mais pas cloneable.

Si un objet a une identité unique en dehors du cadre du processus, vous ne voulez pas, comme une représentation en mémoire d'un enregistrement de base de données à être cloneable parce que c'est équivalent à faire un nouveau record avec des attributs identiques, y compris les attributs identitaires comme la clé de base de données, ce qui est presque jamais la bonne chose. En même temps, vous pouvez avoir un système cassé en plusieurs processus de stabilité ou d'autres raisons, vous pouvez avoir un processus de parler à la base de données et la génération de ces objets « entité » (Voir « Domain-Driven Design » par Eric Evans pour plus informations sur le maintien de la cohérence de l'identité de l'objet dans une application soutenue par des données), mais un processus distinct peut utiliser ces objets pour effectuer des opérations de logique métier. L'objet entité devrait être sérialisable pour qu'il soit passé d'un processus à l'autre.

Je pense que les interfaces sérializable et Cloneable devraient être utilisés à des fins tout à fait différentes. Et si vous avez une classe complexe, puis la mise en œuvre chacun d'eux est pas si facile. Ainsi, en cas général, il dépend des buts.

L'un des plus gros problèmes avec Serializable est qu'ils ne peuvent pas être facilement fait immuable. forces de sérialisation vous de faire un compromis ici.

Je serais tenté de créer des constructeurs de copie vers le bas le graphe d'objet. Il est juste un peu plus gros du travail à faire.

Cela me frappe comme une sorte de dangereux, car il y a un certain nombre de pièges à sérialisation, (bien que la plupart d'entre eux sont peu probables, je veux toujours tester pour eux si je sérialisation des objets dans les bibliothèques du parti 3d). Pas susceptible d'être un problème commun, mais il est possible d'avoir un objet avec une variable volatile dans le cadre de son état qui pourrait faire partie d'une opération de clonage (pas que ce soit une bonne conception, juste qu'il est possible), et comme un champ ne sont copiés dans un processus sérialisation / désérialisation. Une autre question qui vient à l'esprit est énumérations, constantes, et la possibilité d'obtenir des copies multiples de ces choses si vous ne traitez pas avec eux lors de la désérialisation.

Encore une fois, les cas de pointe, mais quelque chose que vous voulez surveiller.

Je viens de penser à un autre cas - Quand il est un ENUM .

Ou plus généralement, lorsque votre classe implémente

scroll top