Properties props1 = new Properties();
props1.setProperty("test1", "test1");
System.err.println(props1.hashCode());
Ce code m'affiche 0 sur la sortie!
autrement dit, il semblerait que la classe Properties ne respecte pas
son contrat. En effet, dans la documentation officiel, il est dit que
Properties.hashCode() "Returns the hash code value for this Map as per
the definition in the Map interface". L'interface Map definit hashCode()
comme suit: "Returns the hash code value for this map. The hash code of
a map is defined to be the sum of the hashCodes of each entry in the
map's entrySet view. This ensures that t1.equals(t2) implies that
t1.hashCode()==t2.hashCode() for any two maps t1 and t2, as required by
the general contract of Object.hashCode."
Or, ce contrat n'est clairement pas respecté, je ne comprends pas
pourquoi...
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
alexandre cartapanis
Bonjour, J'ai une erreur tres tres etrange:
Properties props1 = new Properties(); props1.setProperty("test1", "test1"); System.err.println(props1.hashCode());
Ce code m'affiche 0 sur la sortie!
autrement dit, il semblerait que la classe Properties ne respecte pas son contrat. En effet, dans la documentation officiel, il est dit que Properties.hashCode() "Returns the hash code value for this Map as per the definition in the Map interface". L'interface Map definit hashCode() comme suit: "Returns the hash code value for this map. The hash code of a map is defined to be the sum of the hashCodes of each entry in the map's entrySet view. This ensures that t1.equals(t2) implies that t1.hashCode()==t2.hashCode() for any two maps t1 and t2, as required by the general contract of Object.hashCode."
Or, ce contrat n'est clairement pas respecté, je ne comprends pas pourquoi...
Quelqu'un a t'il une idée du pourquoi?
Bon ben j'ai compris pourquoi: si la valeur et la clé sont egales, alors la methode de calcul implique que hashCode=0. En effet, il fait la somme de chaque Map.Entry, et Map.Entry.hashCode calcul la valeur en utilisant:
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
Bonjour,
J'ai une erreur tres tres etrange:
Properties props1 = new Properties();
props1.setProperty("test1", "test1");
System.err.println(props1.hashCode());
Ce code m'affiche 0 sur la sortie!
autrement dit, il semblerait que la classe Properties ne respecte pas
son contrat. En effet, dans la documentation officiel, il est dit que
Properties.hashCode() "Returns the hash code value for this Map as per
the definition in the Map interface". L'interface Map definit hashCode()
comme suit: "Returns the hash code value for this map. The hash code of
a map is defined to be the sum of the hashCodes of each entry in the
map's entrySet view. This ensures that t1.equals(t2) implies that
t1.hashCode()==t2.hashCode() for any two maps t1 and t2, as required by
the general contract of Object.hashCode."
Or, ce contrat n'est clairement pas respecté, je ne comprends pas
pourquoi...
Quelqu'un a t'il une idée du pourquoi?
Bon ben j'ai compris pourquoi: si la valeur et la clé sont egales, alors
la methode de calcul implique que hashCode=0. En effet, il fait la somme
de chaque Map.Entry, et Map.Entry.hashCode calcul la valeur en utilisant:
Properties props1 = new Properties(); props1.setProperty("test1", "test1"); System.err.println(props1.hashCode());
Ce code m'affiche 0 sur la sortie!
autrement dit, il semblerait que la classe Properties ne respecte pas son contrat. En effet, dans la documentation officiel, il est dit que Properties.hashCode() "Returns the hash code value for this Map as per the definition in the Map interface". L'interface Map definit hashCode() comme suit: "Returns the hash code value for this map. The hash code of a map is defined to be the sum of the hashCodes of each entry in the map's entrySet view. This ensures that t1.equals(t2) implies that t1.hashCode()==t2.hashCode() for any two maps t1 and t2, as required by the general contract of Object.hashCode."
Or, ce contrat n'est clairement pas respecté, je ne comprends pas pourquoi...
Quelqu'un a t'il une idée du pourquoi?
Bon ben j'ai compris pourquoi: si la valeur et la clé sont egales, alors la methode de calcul implique que hashCode=0. En effet, il fait la somme de chaque Map.Entry, et Map.Entry.hashCode calcul la valeur en utilisant:
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
Laurent Bossavit
Alexandre,
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des collision de hachage sont parfaitement possibles.)
Laurent
Alexandre,
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose
probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique
l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des
collision de hachage sont parfaitement possibles.)
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des collision de hachage sont parfaitement possibles.)
Laurent
alexandre cartapanis
Alexandre,
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des collision de hachage sont parfaitement possibles.)
Laurent
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
Alexandre,
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose
probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique
l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des
collision de hachage sont parfaitement possibles.)
Laurent
Effectivement, je me suis un peu emballé dans mon premier post. Le
contrat est respecté, mais bon, la methode de calcul je la trouve un peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
Est-ce que l'on peut considerer ca comme un bug? Parce que ca me pose probleme la...
En quoi est-ce que le contrat n'est pas respecté ?
(La règle pour un hash est que l'identité de deux valeurs implique l'identité de leurs deux hash, mais bien évidemment pas l'inverse. Des collision de hachage sont parfaitement possibles.)
Laurent
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
Syrion
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille <= int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le
contrat est respecté, mais bon, la methode de calcul je la trouve un peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la
répartition n'est aps super (nombre de collision supérieur).
L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe
si le hashCode est problématique pour les perf (l'attribut calculé
mémorisant le hashCode tant que les attributs ne changent pas).
Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias
"Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de
valua tion à 0 de ts les attributs, il faut toujours initialiser avec
une constante.
int hashCode(){
int result; //traditionnellement un nb premier
result*result+champ1;//si champ1 est de type primitif de taille <= int
result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un
type objet.
//etc...
return result;
}
On peut rajouter des champs (boolean isHashComputed et int computedHash)
pour éviter de recalculer à chaque fois si le hashCode est consommateur
en CPU. ne pas oublier de remettre isHashComputed à false si un champ
pris en compte dans hashCode() (et donc dans equals(Object)) change.
+ à rajouter sur le tas une synchronisation si contexte multi-thread
dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur
ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous
hachez avec ^, les perfs de vos maps seront médiocres (collisions plus
nombreuses).
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille <= int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
alexandre cartapanis
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille <= int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17; res = 37 * res + this.name.hashCode(); res += 17; for (Map.Entry<?, ?> entry: this.props.entrySet()) { res += 17; res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + (entry.getValue() == null ? 0 : entry.getValue().hashCode()); } res += 17; return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que c'est un peu plus long a calculer...
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le
contrat est respecté, mais bon, la methode de calcul je la trouve un peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la
répartition n'est aps super (nombre de collision supérieur).
L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe
si le hashCode est problématique pour les perf (l'attribut calculé
mémorisant le hashCode tant que les attributs ne changent pas).
Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias
"Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de
valua tion à 0 de ts les attributs, il faut toujours initialiser avec
une constante.
int hashCode(){
int result; //traditionnellement un nb premier
result*result+champ1;//si champ1 est de type primitif de taille <= int
result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un
type objet.
//etc...
return result;
}
On peut rajouter des champs (boolean isHashComputed et int computedHash)
pour éviter de recalculer à chaque fois si le hashCode est consommateur
en CPU. ne pas oublier de remettre isHashComputed à false si un champ
pris en compte dans hashCode() (et donc dans equals(Object)) change.
+ à rajouter sur le tas une synchronisation si contexte multi-thread
dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur
ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous
hachez avec ^, les perfs de vos maps seront médiocres (collisions plus
nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17;
res = 37 * res + this.name.hashCode();
res += 17;
for (Map.Entry<?, ?> entry: this.props.entrySet()) {
res += 17;
res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) +
(entry.getValue() == null ? 0 : entry.getValue().hashCode());
}
res += 17;
return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que
c'est un peu plus long a calculer...
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille <= int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17; res = 37 * res + this.name.hashCode(); res += 17; for (Map.Entry<?, ?> entry: this.props.entrySet()) { res += 17; res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + (entry.getValue() == null ? 0 : entry.getValue().hashCode()); } res += 17; return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que c'est un peu plus long a calculer...
Je ne saurais te dire, Josh Blosh reste évasif sur le sujet. j'imagine
que ça a un sens pour un matheux, et vu qu'on utilise une hash avec multiplication ça doit avoir un rôle... mais ça serait très intéressant de creuser ! Peut-être en cherchant du côté des hash sécurisé aura-t-on un élément de réponse (là les algos sont chiadés à mort et chaque détail joue un rôle). En tout cas le bouquin "Java efficace" de Josh Blosh ne précise pas si ça joue en faveur d'une algo de hash + fort. J'ai adopté cette astuce parcequ'avant de lire le livre de Josh j'utilisais déjà les nbs premier parceque je trouvait ça marrant dans les hash... si ça se trouve c'est juste un moyen pour les connaisseurs de frimer, mais dans le doute j'utilise les nbs premiers.
Hervé AGNOUX wrote:
Syrion wrote:
int result; //traditionnellement un nb premier
Pourquoi ? (pour ma culture générale)
Je ne saurais te dire, Josh Blosh reste évasif sur le sujet. j'imagine
que ça a un sens pour un matheux, et vu qu'on utilise une hash avec
multiplication ça doit avoir un rôle... mais ça serait très intéressant
de creuser !
Peut-être en cherchant du côté des hash sécurisé aura-t-on un élément de
réponse (là les algos sont chiadés à mort et chaque détail joue un
rôle). En tout cas le bouquin "Java efficace" de Josh Blosh ne précise
pas si ça joue en faveur d'une algo de hash + fort. J'ai adopté cette
astuce parcequ'avant de lire le livre de Josh j'utilisais déjà les nbs
premier parceque je trouvait ça marrant dans les hash... si ça se trouve
c'est juste un moyen pour les connaisseurs de frimer, mais dans le doute
j'utilise les nbs premiers.
Je ne saurais te dire, Josh Blosh reste évasif sur le sujet. j'imagine
que ça a un sens pour un matheux, et vu qu'on utilise une hash avec multiplication ça doit avoir un rôle... mais ça serait très intéressant de creuser ! Peut-être en cherchant du côté des hash sécurisé aura-t-on un élément de réponse (là les algos sont chiadés à mort et chaque détail joue un rôle). En tout cas le bouquin "Java efficace" de Josh Blosh ne précise pas si ça joue en faveur d'une algo de hash + fort. J'ai adopté cette astuce parcequ'avant de lire le livre de Josh j'utilisais déjà les nbs premier parceque je trouvait ça marrant dans les hash... si ça se trouve c'est juste un moyen pour les connaisseurs de frimer, mais dans le doute j'utilise les nbs premiers.
Patrick Gras
Hello,
Pour se simplifier la vie, utiliser org.apache.commons.lang.builder.HashCodeBuilder
L'algo est le même mais c'est plus 'agréable' à utiliser...
-Patrick "alexandre cartapanis" wrote in message news:431d494e$0$17204$
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille < int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17; res = 37 * res + this.name.hashCode(); res += 17; for (Map.Entry<?, ?> entry: this.props.entrySet()) { res += 17; res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + (entry.getValue() == null ? 0 : entry.getValue().hashCode()); } res += 17; return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que c'est un peu plus long a calculer...
Hello,
Pour se simplifier la vie, utiliser
org.apache.commons.lang.builder.HashCodeBuilder
L'algo est le même mais c'est plus 'agréable' à utiliser...
-Patrick
"alexandre cartapanis" <alexandre.cartapanis@macymed.fr> wrote in message
news:431d494e$0$17204$8fcfb975@news.wanadoo.fr...
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le
contrat est respecté, mais bon, la methode de calcul je la trouve un
peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd
meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la
répartition n'est aps super (nombre de collision supérieur).
L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe
si le hashCode est problématique pour les perf (l'attribut calculé
mémorisant le hashCode tant que les attributs ne changent pas).
Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias
"Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de
valua tion à 0 de ts les attributs, il faut toujours initialiser avec
une constante.
int hashCode(){
int result; //traditionnellement un nb premier
result*result+champ1;//si champ1 est de type primitif de taille < int
result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un
type objet.
//etc...
return result;
}
On peut rajouter des champs (boolean isHashComputed et int computedHash)
pour éviter de recalculer à chaque fois si le hashCode est consommateur
en CPU. ne pas oublier de remettre isHashComputed à false si un champ
pris en compte dans hashCode() (et donc dans equals(Object)) change.
+ à rajouter sur le tas une synchronisation si contexte multi-thread
dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur
ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous
hachez avec ^, les perfs de vos maps seront médiocres (collisions plus
nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17;
res = 37 * res + this.name.hashCode();
res += 17;
for (Map.Entry<?, ?> entry: this.props.entrySet()) {
res += 17;
res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) +
(entry.getValue() == null ? 0 : entry.getValue().hashCode());
}
res += 17;
return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que
c'est un peu plus long a calculer...
L'algo est le même mais c'est plus 'agréable' à utiliser...
-Patrick "alexandre cartapanis" wrote in message news:431d494e$0$17204$
alexandre cartapanis wrote:
Effectivement, je me suis un peu emballé dans mon premier post. Le contrat est respecté, mais bon, la methode de calcul je la trouve un peu
bancal. Je veux bien qu'un "^" soit plus rapide qu'un "+" mais qd meme...
^ est plus rapide mais effectivement ce n'est pas très bon car la répartition n'est aps super (nombre de collision supérieur). L'idéal, C'est * et + combinés, avec un attribut calculé dans la classe si le hashCode est problématique pour les perf (l'attribut calculé mémorisant le hashCode tant que les attributs ne changent pas). Josh Blosh (le mec qui a conçu l'API java.lang.util de Java 1.2 (alias "Collections framework") recommande l'usage de * et + combiné.
Comme de plus il est mauvais de retourner 0 en cas de nullité ou de valua tion à 0 de ts les attributs, il faut toujours initialiser avec une constante. int hashCode(){ int result; //traditionnellement un nb premier result*result+champ1;//si champ1 est de type primitif de taille < int result*result+champ2!=null?champ2.hashCode():0;//si champ2 est un type objet. //etc... return result; }
On peut rajouter des champs (boolean isHashComputed et int computedHash) pour éviter de recalculer à chaque fois si le hashCode est consommateur en CPU. ne pas oublier de remettre isHashComputed à false si un champ pris en compte dans hashCode() (et donc dans equals(Object)) change. + à rajouter sur le tas une synchronisation si contexte multi-thread dans ce cas précis.
Notez que pour les attributs long on coupe en 2 int (et on fait un ^ sur ces derniers, ou on considère que ce sont 2 champs différents)
pour les double et float, récupérer leur valeur en tableau de byte
pour les tableau ça peut être long, d'où l'idée de mémoriser le hash.
Voilà, ^ n'est donc pas l'idéal, même si c'est ultra rapide. si vous hachez avec ^, les perfs de vos maps seront médiocres (collisions plus nombreuses).
ben moi c'est toujours ce que je fais :)
Voila comment j'ai resolu le probleme:
int res = 17; res = 37 * res + this.name.hashCode(); res += 17; for (Map.Entry<?, ?> entry: this.props.entrySet()) { res += 17; res += (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + (entry.getValue() == null ? 0 : entry.getValue().hashCode()); } res += 17; return res;
Ca correspond tout a fais au recommandation de Blosh, mais c'est sur que c'est un peu plus long a calculer...