Quelle est la manière correcte de substituer hashCode () et equals () méthodes d'entité persistante?
J'ai une classe simple Rôle:
@Entity
@Table (name = "ROLE")
public class Role implements Serializable {
@Id
@GeneratedValue
private Integer id;
@Column
private String roleName;
public Role () { }
public Role (String roleName) {
this.roleName = roleName;
}
public void setId (Integer id) {
this.id = id;
}
public Integer getId () {
return id;
}
public void setRoleName (String roleName) {
this.roleName = roleName;
}
public String getRoleName () {
return roleName;
}
}
Maintenant, je veux remplacer ses méthodes equals et hashCode. Ma première suggestion est:
public boolean equals (Object obj) {
if (obj instanceof Role) {
return ((Role)obj).getRoleName ().equals (roleName);
}
return false;
}
public int hashCode () {
return id;
}
Mais quand je créer un nouveau Rôle de l'objet, son id est null. C'est pourquoi j'ai un problème avec le hashCode de la méthode de la mise en œuvre. Maintenant, je peux tout simplement le retour roleName.hashCode ()
mais que faire si roleName n'est pas nécessaire de champ? Je suis presque sûr que ce n'est pas si difficile de faire plus compliqué exemple qui ne peut pas être résolu par le retour de hashCode de l'un de ses champs.
Donc j'aimerais voir quelques liens vers des discussions ou à entendre votre expérience de la résolution de ce problème. Merci!
source d'informationauteur Roman | 2009-12-18
Vous devez vous connecter pour publier un commentaire.
Bauer et du Roi livre Java Persistance avec Hibernate conseille de ne pas utiliser le champ clé de equals et hashCode. Ils conseillent, vous devriez choisir ce qui serait l'objet d'affaires de la clé des champs (si il n'y a rien d'artificiel, de la clé) et utilisez-les pour tester l'égalité. Dans ce cas, si le nom de rôle n'a pas été nécessaire de champ, vous trouverez les champs qui ont été nécessaires et de les utiliser en combinaison. Dans le cas de la code vous post où rolename est tout ce que vous avez en plus de l'id, rolename serait ce que je ferais avec.
Voici une citation de la page 398:
Un moyen facile je utiliser pour construire un equals et hashcode de la méthode est de créer une méthode toString qui renvoie les valeurs de la " clé des champs, utilisez-la dans la equals() et hashCode() méthodes. PRÉCISIONS: C'est un paresseux approche pour quand je ne suis pas préoccupé par la performance (par exemple, dans rinky-dink interne webapps), si la performance devrait être un problème, alors écrire les méthodes vous-même ou utiliser votre IDE installations de génération de code.
Je suis désolé pour sauter à la fin avec la critique, mais personne ne l'a mentionné, et il y a un grave défaut ici. Peut-être deux, en fait.
Premier, d'autres ont mentionné comment gérer la possibilité de valeur null, mais un élément essentiel d'une bonne
hashcode()
etequals()
méthode de paire, c'est qu'ils doivent obéir au contrat, et votre code ci-dessus ne fait pas cela.Le contrat est que objets pour lesquels
equals()
retourne true doit retourner l'égalité des hashcode valeursmais dans votre classe au-dessus, les champs id et roleName sont indépendants.C'est viciée pratique: vous pouvez facilement avoir deux objets avec le même roleName valeur, mais différentes valeurs d'id.
La pratique est d'utiliser les mêmes domaines, afin de générer le hashcode de la valeur que sont utilisés par la méthode equals (), et dans le même ordre. Ci-dessous mon remplacement pour votre méthode hashcode:
Note: je ne sais pas ce que vous avez prévu par l'utilisation de l'id de champ comme hashcode, ou ce que vous vouliez faire avec le champ id. Je vois de l'annotation que c'est générée, mais il est externe générée, donc la classe comme l'écrit ne parvient pas à remplir le contrat.
Si, pour quelque raison que vous vous trouvez dans une situation où cette classe est exclusivement géré par un autre qui fidèlement génère "id" valeurs pour roleNames qui ne remplir le contrat, vous n'auriez pas un problème fonctionnel, mais ce serait toujours une mauvaise pratique, ou du moins, ce que les gens appellent "odeur de code". Outre le fait qu'il n'y a rien dans la définition de classe pour garantir que la classe est uniquement utilisable dans de cette façon, hashcodes ne sont pas les id, de sorte que les id ne sont pas hashcodes.
Cela ne signifie pas que vous ne pouvez pas utiliser une garantie d'égal-à-égal-rolename-les valeurs de l'identificateur de comme le hashcode, mais ils ne sont pas essentiellement les mêmes, de sorte que, à tout le moins, vous devriez avoir un bloc de commentaire pour expliquer votre départ de pratique courante.
Et comme une bonne règle générale, si vous vous trouvez avoir à le faire, vous avez probablement fait une erreur de conception. Pas toujours, mais probablement. Une raison à cela? Les gens n'ont pas toujours lu les commentaires, donc, même si vous créez le parfait fonctionnement du système, au fil du temps, ce sera quelqu'un "détournement" de votre classe et de causer des problèmes.
Avoir la classe elle-même de gérer la génération de hashcode valeurs évite que. Et pourtant, on pourrait enregistrer et de les rendre disponibles à l'extérieur id généré, quel que soit le but de l'utiliser.
La clé d'entreprise d'un objet peut exiger de ses parents (ou d'une autre un-à-un ou plusieurs-à-une) relation. Dans ces cas, l'appel est égal à() ou hashcode() pourrait entraîner une base de données de frapper. Outre la performance, si la fermeture de la session qui va provoquer une erreur. J'ai surtout renoncé à utiliser les clés d'entreprise; - je utiliser l'id primaire et éviter d'utiliser des entités enregistrées dans les cartes et ensembles. A bien fonctionné jusqu'à présent, mais cela dépend probablement sur l'application (attention lors de l'enregistrement de plusieurs enfants par le parent en cascade). Parfois, je vais utiliser un autre sens champ de clé c'est un uuid auto-généré dans le constructeur ou par l'objet créateur.
Savoir quand vous écrasez le hashCode et equals est pas une tâche facile,
il y a une autre discussion où vous avez l'exemple et la documentation en lien ici Quelles questions devraient être examinées lors de la substitution equals et hashCode en Java?
Comme déjà mentionné, vous devez utiliser une clé d'entreprise pour mettre en œuvre l'égalité et hashCode. En outre, vous avez pour faire de votre equals et hashCode de la mise en œuvre null-safe ou ajouter pas null contraintes (et invariants des vérifications dans votre code) de s'assurer que la clé d'entreprise n'est jamais null.
Je suppose que l'ajout de contraintes est la bonne approche pour votre problème. Sinon, les instances de Rôle sans noms seront autorisées et toutes ces instances seraient considérées comme égales.
Veuillez trouver ci-dessous les instructions simples comment créer hashCode, d'égal à égal et toString méthodes à l'aide d'Apache commons constructeurs.
hashCode
Vous pouvez appeler pour .appendSuper(super.hashCode()) dans le cas où votre classe est sous-classe
est égal à
Vous pouvez appeler pour .appendSuper(super.equals(autres)) dans le cas où votre classe est sous-classe
toString
Vous pouvez appeler pour .appendSuper(super.toString()) dans le cas où votre classe est sous-classe