IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

[Reference][String][Integer] Qu'est ce vraiment ?


Sujet :

Langage Java

  1. #1
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut [Reference][String][Integer] Qu'est ce vraiment ?
    Bonjour à tous,

    Je m'interroge sur le principe des comparaisons par référence ( == ).
    Je viens de faire le test suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    		String t1 = new String("toto");
    		String t2 = new String("toto");
     
    		System.out.println(t1.hashCode());
    		System.out.println(t2.hashCode());
    		System.out.println(t1==t2);
    Je pense que je me trompe, mais pour moi la référence (sur lequel se faisait le contrôle) était lié au hashcode de l'objet.
    Or pour les String, il s'avère que dans mon exemple t1 et t2 , ont le même hashCode , mais ne sont pourtant pas égaux par référence ( t1==t2 -> false).
    Donc ma question est la suivante , comment faire pour savoir ce qu'il compare dans le cas des références.
    Il me semblait pourtant que dans le cas des String et aussi Integer, Float etc... , Java utilisait un pool d'objet pour optimiser sa mémoire, ce qui permettait dans le cas des Integer par exemple de faire des comparaisons de références en évitant l'appel à intValue().
    Je ne sais pas vraiment si j'étais clair, mais si quelqu'un peut m'éclairer , je répondrais à toutes les questions que vous vous posez.
    D'avance merci.

    Zekid.

  2. #2
    Membre confirmé Avatar de Satch
    Homme Profil pro
    Hypnothérapeute - Magicien
    Inscrit en
    Mars 2004
    Messages
    498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Hypnothérapeute - Magicien

    Informations forums :
    Inscription : Mars 2004
    Messages : 498
    Points : 645
    Points
    645
    Par défaut
    Le contrat de hashCode est de renvoyer la même valeur si Equals() renvoie true. Rien de plus.

    Et en effet, le compilateur créé un pool de String égales. Mais il regarde uniquement les littéraux.
    Ici, lors de l'éxécution, tes Strings sont créées dynamiquement, donc tu as 2 objets différents, mais qui sont equals, donc de même hashCode.

    Par contre, si tu faisais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String t1 = "toto";
    String t2 = "toto";
    Alors tu aurais t1==t2, car le compilateur aurait placé "toto" dans le pool (car c'est un litéral qu'il peut déterminer à la compilation) et aurait fait pointer t1 et t2 dessus.
    Je sais que désormais vivre est un calembour,
    La mort est devenue un état permanent,
    Le monde est aux fantômes, aux hyènes et aux vautours.
    Moi je vous dis bravo et vive la mort.

  3. #3
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Il y a aussi un pool pour les petits Integer.
    Romain Guy
    Android - Mon livre - Mon blog

  4. #4
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut
    Merci Satch pour ta réponse.
    Et as tu une idée de ce sur quoi porte le test de référence?

  5. #5
    Membre confirmé Avatar de Satch
    Homme Profil pro
    Hypnothérapeute - Magicien
    Inscrit en
    Mars 2004
    Messages
    498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Hypnothérapeute - Magicien

    Informations forums :
    Inscription : Mars 2004
    Messages : 498
    Points : 645
    Points
    645
    Par défaut
    Je ne comprends pas tres bien ta question mais si tu veux savoir ce qu'il fait quand on fait ==, il regarde juste si t1 et t2 (dans ton exemple) pointent sur le même objet.
    Je sais que désormais vivre est un calembour,
    La mort est devenue un état permanent,
    Le monde est aux fantômes, aux hyènes et aux vautours.
    Moi je vous dis bravo et vive la mort.

  6. #6
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut
    En fait ma question est de savoir s'il y a moyen ou non de savoir comment lui il fait son contrôle. Sur quoi ? Sur la mémoire probablement ?

  7. #7
    Membre chevronné
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    940
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 940
    Points : 1 817
    Points
    1 817
    Par défaut
    Attention, vous confondez certaines choses.

    La référence et le hashcode sont deux choses différentes. La référence permet de trouver où se trouve un objet en mémoire. Le hashcode est un code créé à partir de la valeur d'un objet. Souvent utilisé pour classer un objet, rien n'indique qu'il soit utilisé par la machine virtuelle pour sa gestion mémoire.

    Deux objets peuvent être identiques mais avoir des références différentes. Si Jean et Tom sont jumeaux, leurs noms sont quand même différents.

    Il me semblait pourtant que dans le cas des String et aussi Integer, Float etc... , Java utilisait un pool d'objet pour optimiser sa mémoire, ce qui permettait dans le cas des Integer par exemple de faire des comparaisons de références en évitant l'appel à intValue().
    JAMAIS une méthode d'optimisation de la machine virtuelle ne changera le comportement d'une application. Le foctionnement interne d'une JVM est et doit être entièrement transparent. Par ailleurs, comparer les références quand on veut en fait comparer les valeurs est un excellent moyen d'écrire du code impossible à maintenir et bogué.

    Edit : posts simultanés.

  8. #8
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Certes mais quand on connait le fonctionnement des == et des references cela permet parfois d'optimiser de belle maniere des algorithmes, notamment avec les String par rapport a equals(). Cela m'est arrive une fois de recourir explicitement a == plutot qu'equals() mais dans ce cas la il vaut mieux bien documenter son code.

    Bref, pour en revenir aux Integer prenez ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Integer i1 = 1;
    Integer i2 = 1;
     
    System.out.println(i1 == i2);
     
    Integer i3 = 462;
    Integer i4 = 462;
     
    System.out.println(i3 == i4);
    A votre avis il affche quoi ?

    Il affichera true et false. Car pour les Integer < 127 (si je me souviens bien), la JVM peut faire comme pour les String, et les placer dans un poo. On utilise donc la meme reference pour des petits nombres mais plus pour des "grands".

    Bref, comme le dit BugFactory, autant eviter l'utilisation de ==, sauf avec null.
    Romain Guy
    Android - Mon livre - Mon blog

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    940
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 940
    Points : 1 817
    Points
    1 817
    Par défaut
    Pour répondre à votre dernière question, je vous conseille de lire les spécifications de la JVM sur le site de Sun Microsystem. Veuillez noter que faire un programme destiné à tire parti d'une seule JVM est une mauvaise idée car rien ne garantit que les autres JVM se comporteront de manière identique.

  10. #10
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par BugFactory
    Veuillez noter que faire un programme destiné à tire parti d'une seule JVM est une mauvaise idée car rien ne garantit que les autres JVM se comporteront de manière identique.
    +1

    Surtout que rien ne permet d'affirmer quelque soit la JVM les valeurs qui seront en cache de celle qui ne le seront pas...

    Bref pour les objets il faut toujours comparer avec la méthode equals(). Eventuellement on peut toujours utiliser une comparaison de référence dans cette dernière pour éviter de comparer tous les champs lorsqu'il s'agit du même objet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public boolean equals(Object object) {
     
    	boolean res = false;
    	if (this==object) {
    		res = true;
    	} else 	if (object instanceof MaClasse) {
    		MaClasse other = (MaClasse) object;
     
    		// Comparaison des champs utiles...
    		res = ...
     
    	}
    	return res;
    }

    Et la comparaison via == ne devrait être utilisé que dans les cas suivant :
    • Pour vérifier que la référence n'est pas |b]null[/b].
    • Pour comparer des types primitifs (int, long, etc...).
    • Pour comparer des enum de Java 5.0.


    a++

  11. #11
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Tu fais bien de preciser avec un bout de code. L'implementation recommandee de equals() est de commencer par faire un test d'identite (== donc). Cf le bouquin Effective Java.

    Il ne faut quand meme pas jeter l'utilisation de == avec des instances de classe. Cela peut servir dans certains cas, notamment avec des collections. Par exemple pour tester que l'objet que l'on dessine est le dernier d'une pile (if (shape == shapesStack.peek()), etc. Mais bon c'est comme toutes les autres subtilites de Java (ou des langages informatiques en general), elles sont utiles mais il faut apprendre ce que c'est avant de les utiliser.
    Romain Guy
    Android - Mon livre - Mon blog

  12. #12
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut
    Oh là !!!!
    Je ne cherche pas à faire du code de mer.... Je cherche juste à savoir.
    Il me semblait seulement avoir lu que c'était possible de faire des comparaisons de référence directement sur les objets pour les types Integer, Float etc...
    Comme je le fais avec les int, float etc....
    Cela paraitrait assez logique que Java prévoit ce genre de chose, il n'y aurait rien de choquant là dedans. Après tout , je pense que Integer(0) ne peut décemment pas avoir la valeur 2. Enfin c'est mon avis....
    En tout cas , il se trouve que là plupart des développeurs prennent en considération la référence comme étant ce que l'on affiche quand on fait obj.toString(). Un truc du genre monpackage.maclasse@hashCodeHexa.
    Et de manière général, par abus de language , on dit que c'est la référence. Mais ce n'est donc pas véritablement le cas....
    Sauf si je suis le seul à avoir fait le raccourci, mais je pense que cela nécessitait une explication.
    En tout cas merci à tous pour vos réponses.

  13. #13
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut
    Citation Envoyé par BugFactory
    Veuillez noter que faire un programme destiné à tire parti d'une seule JVM est une mauvaise idée car rien ne garantit que les autres JVM se comporteront de manière identique.
    Loin de moi cette idée. Je pensais que c'était dans les SPECS Java, c'est tout.

  14. #14
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ZeKiD
    Il me semblait seulement avoir lu que c'était possible de faire des comparaisons de référence directement sur les objets pour les types Integer, Float etc...
    C'est "possible" grâce au cache... mais il y a de forte chance que ton programme puisse poser problème...
    Tous les objets qui sont créé via un new ne pourront pas apprtenir à ce cache.

    De plus à ma connaissance rien n'est définit pour la gestion de ces caches... il se peut même que ce ne soit pas implémenté dans certaines JVM...


    Citation Envoyé par ZeKiD
    Cela paraitrait assez logique que Java prévoit ce genre de chose, il n'y aurait rien de choquant là dedans. Après tout , je pense que Integer(0) ne peut décemment pas avoir la valeur 2. Enfin c'est mon avis....
    Oui mais un autre objet Integer peut bien avoir la valeur 0. Et la comparaison par référence t'indiquerai qu'ils sont différents...

    Pour les objets :
    • == Vérifie l'identité de l'objet (a==b signifie que a et b correspondent au même objet en mémoire).
    • equals() vérifie l'égalité, (a.equals(b) signifie que la valeur de a est identique à la valeur de b, même s'il peuvent correspondre à des objets différents en mémoire).



    Citation Envoyé par ZeKiD
    En tout cas , il se trouve que là plupart des développeurs prennent en considération la référence comme étant ce que l'on affiche quand on fait obj.toString(). Un truc du genre monpackage.maclasse@hashCodeHexa.
    Et de manière général, par abus de language , on dit que c'est la référence. Mais ce n'est donc pas véritablement le cas....
    C'est en partie vrai...

    La documentation de Object.hashCode() indique que la méthode doit retourner un identifiant unique pour chaque objet en mémoire. L'implémentation par défaut utilise pour cela l'adresse mémoire de l'objet, mais ce n'est en aucun cas une obligation (ce pourrait très bien être un compteur).

    Par contre il est faux de dire que le hashCode correpond à la référence de l'objet. Ce n'est que l'implémentation par défaut de la méthode hashCode() qui renvoit quelquechose qui peut s'en approcher. La méthode hashCode() est redéfini dans la plupart des classes conteneurs de l'API, et devrait l'être dans les classes personnels...

    Le but de hashCode() est tout autre : c'est de permettre de stocker des objets dans des Map (les Map utilisent les hashCode des clefs pour retrouver plus vite les objets).

    a++

  15. #15
    Membre confirmé Avatar de Satch
    Homme Profil pro
    Hypnothérapeute - Magicien
    Inscrit en
    Mars 2004
    Messages
    498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Hypnothérapeute - Magicien

    Informations forums :
    Inscription : Mars 2004
    Messages : 498
    Points : 645
    Points
    645
    Par défaut
    Juste en passant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public int hashCode(){
       return 1;
    }
    est une implémentation correcte (vis à vis du contrat) de hashCode pour n'importe quelle classe.

    Ca m'a toujours amusé de savoir ça, même si le faire c'est pas très malin ;)
    Je sais que désormais vivre est un calembour,
    La mort est devenue un état permanent,
    Le monde est aux fantômes, aux hyènes et aux vautours.
    Moi je vous dis bravo et vive la mort.

  16. #16
    Membre averti
    Inscrit en
    Mars 2004
    Messages
    377
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 377
    Points : 356
    Points
    356
    Par défaut
    Citation Envoyé par adiGuba
    La documentation de Object.hashCode() indique que la méthode doit retourner un identifiant unique pour chaque objet en mémoire.
    Autant dire alors que les Integer ne respecte pas le contrat alors !!!
    Puisque qu'il renvoit la valeur de l'Integer , alors que les objets sont différents en mémoire.

    Je comprends toujours pas pourquoi pour les objets issues de type primitifs , == ne fonctionne pas comme avec les types primitifs eux même. Sauf peut-être avec l'autoboxing en jdk 1.5.....

  17. #17
    Membre confirmé Avatar de Satch
    Homme Profil pro
    Hypnothérapeute - Magicien
    Inscrit en
    Mars 2004
    Messages
    498
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Hypnothérapeute - Magicien

    Informations forums :
    Inscription : Mars 2004
    Messages : 498
    Points : 645
    Points
    645
    Par défaut
    Citation Envoyé par ZeKiD
    Citation Envoyé par adiGuba
    La documentation de Object.hashCode() indique que la méthode doit retourner un identifiant unique pour chaque objet en mémoire.
    Autant dire alors que les Integer ne respecte pas le contrat alors !!!
    Puisque qu'il renvoit la valeur de l'Integer , alors que les objets sont différents en mémoire.
    Je crois qu'il s'est mal exprimé. Par identifiant unique, il voulait dire que pour un même objet cet identifiant sera toujours le même, si l'objet n'a pas changé d'état.

    Ensuite pour cette histoire de ==, il faut bien comprendre que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String s1="huhu";
    String s2="huhu";
    Dans ce cas, oui ça retourne true. Mais il faut garder à l'esprit que ce n'est qu'une optimisation du compilateur, qui lui évite de créer 2 objets "huhu".
    Sauf cas exceptionnel, en prenant l'exemple des Strings, toujours utiliser equals(), sauf si on veut vraiment savoir si c'est le même objet en mémoire et pas s'il est pareil.

    Pour les Integer, avec le boxing de la 1.5, le == renvoie true si la valeur est comprise entre -128 et 127 (8 octets) et ceci aussi pour des raisons d'optimisation, et à condition que les valeurs affectées soient des litéraux. exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Integer i1 = 10;
    Integer i2 = 10;
    le test == donnera true.


    Bon je me répète mais pour résumer :
    - Le contrat de hashCode() est de renvoyer un même entier pour 2 objets si ces 2 objets sont equals, rien de plus.
    - le test du == teste si 2 variables référencent le même objet en mémoire
    - pour des raisons d'optimisation, le compilateur fait pointer parfois 2 variables sur un même objet (par exemple pour les Integer entre -128 et 127, ou pour les String) et à condition que ces valeurs puissent être déterminée à la compilation (donc des litéraux, pas de new, pas d'expression avec des variables, etc.)

    Je comprends toujours pas pourquoi pour les objets issues de type primitifs , == ne fonctionne pas comme avec les types primitifs eux même. Sauf peut-être avec l'autoboxing en jdk 1.5.....
    Tout simplement parce que quand tu fais un new qqch() il créé un nouvel objet. donc ça peut pas être == à autre chose


    Edit : en tout cas je trouve ce topic très interressant, je savais pas qu'il optimisait pour les wrappers :)
    Je sais que désormais vivre est un calembour,
    La mort est devenue un état permanent,
    Le monde est aux fantômes, aux hyènes et aux vautours.
    Moi je vous dis bravo et vive la mort.

  18. #18
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Autant dire alors que les Integer ne respecte pas le contrat alors !!!
    Puisque qu'il renvoit la valeur de l'Integer , alors que les objets sont différents en mémoire.
    Ce n'est pas pareil car les Integer, comme les String, sont immuables. Lorsqu'une reference est creee, elle ne changera jamais de valeur. Et comme le dit Satch l'important est que le hashCode soit le meme pour deux valeurs egales. C'est pour ca que si tu surcharges equals() il est conseille de faire de meme pour hashCode().
    Romain Guy
    Android - Mon livre - Mon blog

Discussions similaires

  1. Est-ce vraiment légal ?
    Par pi-2r dans le forum Sécurité
    Réponses: 21
    Dernier message: 13/08/2006, 12h17
  2. getline string integer
    Par Gebudi. dans le forum C++
    Réponses: 9
    Dernier message: 28/05/2006, 08h23
  3. [Firebird]Erreur:la reference d'objet n'est pas definie
    Par monmien dans le forum Bases de données
    Réponses: 2
    Dernier message: 28/02/2006, 09h20
  4. Conversions de String à Integer
    Par Rank dans le forum Langage
    Réponses: 5
    Dernier message: 06/08/2003, 16h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo