web-dev-qa-db-fra.com

java.util.Date clone ou copie pour ne pas exposer la référence interne

Il est préférable de ne pas exposer les références internes d'un objet (entité). Donc, si un objet a un champ de type Java.util.Date, Par exemple, le getter de ce champ ne doit pas renvoyer la date d'origine mais une copie.

Mais pour un Java.util.Date, il existe deux façons courantes de créer cette copie:

  • clone: ​​(Date) originalDate.clone()
  • copier via le constructeur new Date(originalDate.getTime())

Ma question est, quelle est la meilleure voie, et pourquoi?

64
Ralph

Si c'est vraiment juste un Date, cela ne fera aucune différence de toute façon.

Si l'objet réel peut être une sous-classe de Date (comme Java.sql.Date), Alors j'espère que clone() conserverait les informations supplémentaires (y compris de quelle classe il s'agit), contrairement à l'appel du constructeur.

En passant, si vous avez utilisé Joda Time vous n'auriez pas ce problème, car il existe de nombreux types immuables à utiliser. C'est aussi une bien meilleure API :)

43
Jon Skeet

Lire Java efficace . La façon préférée de créer des copies est d'utiliser l'approche du constructeur de copie.

Bill Venners: Dans votre livre, vous recommandez d'utiliser un constructeur de copie au lieu d'implémenter Cloneable et d'écrire un clone. Pouvez-vous développer sur ce sujet?

Josh Bloch: Si vous avez lu l'article sur le clonage dans mon livre, surtout si vous lisez entre les lignes, vous saurez que je pense que le clone est profondément rompu. Il existe quelques défauts de conception, le plus important étant que l'interface Cloneable n'a pas de méthode de clonage. Et cela signifie que cela ne fonctionne tout simplement pas: rendre quelque chose de clonable ne dit rien sur ce que vous pouvez en faire. Au lieu de cela, il dit quelque chose sur ce qu'il peut faire en interne. Il dit que si en appelant super.clone à plusieurs reprises il finit par appeler la méthode de clonage d'Object, cette méthode retournera une copie de champ de l'original.

35
Amir Afghani

Si vous codez défensivement, vous aurez besoin du constructeur de copie. Voir ce passage de Java efficace :

Notez également que nous n'avons pas utilisé la méthode de clonage de Date pour effectuer les copies défensives. Étant donné que Date n'est pas définitif, la méthode clone n'est pas garantie de renvoyer un objet dont la classe est Java.util.Date; il pourrait renvoyer une instance d'une sous-classe non approuvée spécialement conçue pour des méfaits malveillants. Une telle sous-classe pourrait, par exemple, enregistrer une référence à chaque instance dans une liste statique privée au moment de sa création et permettre à l'attaquant d'accéder à cette liste. Cela donnerait à l'attaquant le règne libre sur toutes les instances. Pour éviter ce type d'attaque, n'utilisez pas la méthode clone pour créer une copie défensive d'un paramètre dont le type est sous-classable par les parties non fiables.

15
robpvn