Objet.hash () vs Objects.hashCode (), clarification nécessaire

Ok, donc en Java 7 Nous avons

    o.hashCode();
    Objects.hashCode(o);

    Objects.hash(o);

les 2 premiers sont à peu près les mêmes avec le point nul, mais quel est le dernier?

Lorsqu'une référence à un seul objet est fournie, la valeur retournée ne n'est pas égal au code de hachage de cette référence d'objet.

Pourquoi est-ce? On n'a pas besoin de 3 méthodes qui font la même chose, je comprends .. mais pourquoi avons-nous besoin d' Objects.hash()? Quand vous avez choisi d'utiliser un vs de l'autre?

38
demandé sur JAM 2012-07-22 06:29:58

3 réponses

voir la documentation pour hashCode et hash. hash faut Object...hashCode a Object. L'exemple donné est:

@Override public int hashCode() {
    return Objects.hash(x, y, z);
}
  • Objects.hash(Object... values) doit être utilisé dans les cas où vous voulez un hachage d'une séquence d'objets, par exemple lors de la définition de votre propre hashCode méthode et souhaitez simplement codé de hachage pour plusieurs valeurs qui composent l'identité de votre objet.
  • Objects.hashCode(Object o) doit être utilisé lorsque vous voulez le hachage d'un objet unique, sans jeter si l'objet est null.
  • Object::hashCode() doit être utilisé lorsque vous souhaitez que le hachage d'un objet unique, et lève une exception si l'objet est null.

Notez que hash(o) et hashCode(o) ne sera pas forcément en retour la même chose! Si vous le faites pour un seul objet, vous devriez probablement utiliser hashCode.

61
répondu Tim S. 2017-10-18 09:29:55

le hashCode par défaut() de L'objet renvoie l'adresse mémoire de l'objet. Donc, si vous avez la classe suivante:

class Car {
    String make;
    String model;
    int year;

    public Car(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }
} 

puis créez deux objets:

Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);

car1.le hashCode () sera différent du rac2.hashCode () parce que chaque objet aura une adresse mémoire différente.

et si vous voulez que les deux voitures retournent le même code de hachage? Dans ce cas, vous devriez outrepasser la méthode hashCode objet par défaut() pour la classe de voiture comme suit:

@Override
public int hashCode() {
    Object[] x = {model, make, Integer.valueOf(year)};
    int hashArray = Arrays.hashCode(x);
    return hashArray;
}

cela fera la voiture 1.hashCode () égale à car2.hashCode () parce que la chaîne.hashCode() calcule le hashCode basé sur le contenu de la chaîne, et l'Entier.hashCode() retourne la valeur entière elle-même.

en Java 7, vous pouvez simplement utiliser des objets.hash (Object... valeur.) Aussi notre nouvelle voiture hashCode () aura l'air de ce qui suit:

@Override
public int hashCode() {
    return Objects.hash(model, make, year);
}

Objets.hash (Object... valeurs) appelleront des tableaux.hashCode pour vous.

Enfin, Objet.hashCode (Object o) fera une vérification nulle. Il retournera 0 si l'objet est null. Sinon, il appellera la méthode objects hashCode ().

9
répondu ezzadeen 2018-02-19 05:47:36

Objects.hashCode

la méthode utilitaire Objects.hashCode( Object o ) appelle simplement les hashCode méthode sur l'objet passé.

Tolerates NULL

alors pourquoi inventer ou utiliser cette méthode? Pourquoi ne pas simplement appeler l'objet hashCode méthode vous-même?

Cette méthode offre un avantage: NULL0. La méthode utilitaire tolère un nul. Si vous appelez Objects.hashCode( myObject )myObjectNULL, vous obtenez en retour un zéro (0). En revanche, l'appel de myObject.hashCode() quand myObject null jette un NullPointerException argument.

la question de savoir s'il est souhaitable ou non de tolérer un nul dépend de votre propre jugement et de votre situation particulière.

Objects.hash

la méthode utilitaire Objects.hash( Object o , … ) sert un but différent. Cette méthode comporte deux phases:

  • Appel .hashCode sur chaque objet passé, la collecte de chaque résultat.
  • calculer un hachage sur le collecté résultat.

hash de hash

Si vous passez un objet unique, Objects.hash( myObject ), premier myObject.hashCode est appelé et collecté, puis un hachage sur cette collecte à un seul article est calculé. Donc, vous finissez avec un hachage d'un hachage.

Lorsqu'on hache un seul objet, il est essentiel de comprendre que Objects.hashCode( myObject ) renvoie un résultat différent de Objects.hash( myObject ). En effet, le second renvoie un hachage sur le résultat du premier.

Ennuyeux dans pratique

La logique de l'approche adoptée dans ces deux Objects méthodes de sens en eux-mêmes.

malheureusement, dans la pratique, pour ceux d'entre nous essayant de les utiliser dans l'utilisation quotidienne lors de l'écriture de code sur nos POJOs pour outrepasser hashCode, et, en conséquence equals, nous devons réfléchir à deux fois pour décider qui appeler.

  • Si votre hashCode (et equals) dérogation est basée sur un seul membre de votre classe, utiliser Objects.hashCode( member ).
  • Si votre hashCode (et equals) la commande override est basée sur plusieurs attributs de votre classe, utilisez Objects.hash( memberA , memberB , memberC ).

un Seul membre, ne tolérant pas un NULL

@Override
public int hashCode() {
    return this.member.hashCode() ;  // Throws NullPointerException if member variable is null.
}

un Seul membre, de tolérer un NULL

@Override
public int hashCode() {
    return Objects.hashCode( this.member ) ;  // Returns zero (0) if `this.member` is NULL, rather than throwing exception.
}

Multi-membre

@Override
public int hashCode() {
    return Objects.hash( this.memberA , this.memberB , this.memberC  ) ;  // Hashes the result of all the passed objects’ individual hash codes.  
}

Exemple

nous pouvons tester ces différentes méthodes très simplement.

UUID

utilisons un UUID objet en tant que exemple. UUID ( identificateur universel unique) est une valeur de 128 bits où certains bits ont une certaine sémantique.

OpenJDK mise en oeuvre de UUID représente à l'interne la valeur de 128 bits comme une paire de 64 bits long nombres entiers.

même la mise en œuvre des remplacements Object::equals et Object::hashCode regarder les données stockées dans cette paire d'entiers longs. Voici le code source pour ceux deux méthodes.

public boolean equals(Object obj) {
    if ((null == obj) || (obj.getClass() != UUID.class))
        return false;
    UUID id = (UUID)obj;
    return (mostSigBits == id.mostSigBits &&
            leastSigBits == id.leastSigBits);
}
public int hashCode() {
    long hilo = mostSigBits ^ leastSigBits;
    return ((int)(hilo >> 32)) ^ (int) hilo;
}

exemple de code

instanciez notre objet UUID.

UUID uuid = UUID.randomUUID();

calculez nos valeurs de hachage.

int hash1 = uuid.hashCode();
int hash2 = Objects.hashCode( uuid );  // Result matches line above.

int hash3 = Objects.hash( uuid );  // Returns a hash of a hash.
int hash4 = Objects.hash( uuid.hashCode() ); // Result matches line above.

Dump à console.

System.out.println( "uuid.toString(): " + uuid.toString() );
System.out.println( " 1/2 = " + hash1 + " | " + hash2 );
System.out.println( " 3/4 = " + hash3 + " | " + hash4 );

Voir le code à exécuter en direct à IdeOne.com.

uuid.toString (): 401d88ff-c75d-4607-bb89-1f7a2c6963e1

1/2 = 278966883 | 278966883

3/4 = 278966914 | 278966914

0
répondu Basil Bourque 2018-10-04 20:10:58