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

 Java Discussion :

Problème de cast


Sujet :

Java

  1. #1
    Membre habitué
    Problème de cast
    Bonjour à tous,
    J'ai une erreur à l'exécution :

    Exception in thread "main" java.lang.ClassCastException:

    Sur :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
      tabTrie=(Personne[])Personne.tri(tabObj,new Personne());


    Où tabTrie est

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    Personne[] tabTrie; //Classe Personne


    et tabObj est
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    Object[] tabObj;

    Le but du code

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
      tabTrie=(Personne[])Personne.tri(tabObj,new Personne());


    est d'utiliser une seule méthode ou fonction dans une Interface Comparateur :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    package Cours;
     
    //cette interface devra être implémentée par les classes 
    //pour lesquelles une comparaison des instances est envisagée 
    public interface Comparateur 
    { 
    // cette méthode pourra être appelée pour comparer les deux 
    // objets reçus en paramètre 
    // la méthode retourne un entier dont la valeur dépend 
    // des règles suivantes 
    // 1 si l’instance o1 est supérieure à o2 
    // 0 si les deux instances sont égales 
    // -1 si l’instance o1 est inférieure à o2 
    // -99 si la comparaison est impossible 
      int compare2(Object o1,Object o2); 
     
      public static final int INFERIEUR=-1; 
      public static final int EGAL=0; 
      public static final int SUPERIEUR=1; 
      public static final int ERREUR=-99; 
     
    }
    // Une telle interface qui ne contient que la définition d’une seule 
    // et unique méthode est appelée interface fonctionnelle.

    La méthode ést dans la classe Personne :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    public static Object[] tri(Object[] tablo,Comparateur trieur) 
        { 
             int i,j; 
             Object c; 
             Object[] tabloTri; 
             tabloTri=Arrays.copyOf(tablo,tablo.length); 
            for (i=0;i< tabloTri.length;i++) 
            { 
                for( j = i + 1; j<tabloTri.length;j++) 
                { 
                // utilise la fonction compare de l’objet reçu en paramètre 
                // pour comparer le contenu de deux cases du tableau 
                 if 
        (trieur.compare2(tabloTri[j],tabloTri[i])==Comparateur.INFERIEUR) 
                 { 
                      c = tabloTri[j]; 
                      tabloTri[j] = tabloTri[i]; 
                      tabloTri[i] = c; 
                 } 
                 else if 
        (trieur.compare2(tabloTri[j],tabloTri[i])==Comparateur.ERREUR) 
                 { 
                      return null; 
                 } 
                } 
            } 
             return tabloTri; 
        }

    Je dois pour utiliser cette fonction de tri fournir 2 paramètres :
    - le tableau à trier : tabObj
    - une instance de classe qui implémente l'interface Comparateur : new Personne()
    Si quelqu'un a une idée MERCI

  2. #2
    Modérateur

    Salut,

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    tabTrie=(Personne[])Personne.tri(tabObj,new Personne());

    te donne une ClassCastException parce qu'un tableau d'Object (Object[]) n'est pas castable en tableau de Personne[]. Le cast n'est pas une sorte de conversion. C'est juste un moyen de faire accepter un objet d'un certain type plus générique par une variable typée dans un type plus spécifique pour permettre de manipuler l'objet via ce type spécifique. Spécifique implique qu'il étend le type plus générique. Cela implique bien sûr que l'objet soit de cette classe spécifique.

    On peut caster un object de classe Personne, manipulé par le type Object en classe Personne qui étend Object :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Personne {
     
       public static void main(String[] args) {
     
            Personne personne = (Personne)getPersonne();
     
       }
     
       public static Object getPersonne() {
              return new Personne();
       }
     
    }


    On est obligé de caster parce que le retour de getPersonne() est de type Object. Mais on peut caster parce que l'objet retourné est de classe Personne.

    Un Object[] n'est en rien un Personne[]. Personne[] n'étend pas Object[].

    Par ailleurs pourquoi passer par le type Object, ou Object[] ? Si on doit trier des Personne, pourquoi permettre de trier autre chose ? Surtout des objets de types qui possiblement ne seraient pas comparable via la méthode compare2(Object,Object) ?
    Les types ça sert à ça : à garantir que les objets qu'on a à manipuler ont bien les caractéristiques qu'on voudrait qu'ils aient (les méthodes, les attrbuts, etc).

    Donc normalement :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    public static Personne[] tri(Personne[] tablo,Comparateur trieur)


    Du coup plus besoin de caster.

    Ou alors, sans changer l'implémentation de tri, il faut que le tableau d'origine soit bien un tableau de Personne (un Personne[]), donc dans la méthode d'application :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Object[] tabObj = new Personne[] {new Personne(),new Personne()};
     
     
    Personne[] tabTrie = (Personne[]) Personne.tri(tabObj,new Personne());


    Ici la classe du tableau est bien Personne[], donc on peut caster l'objet tabObj, en Personne[], même si on le manipule par le type Object[].

    Attention, cela fonctionne parce que tu utilises la méthode Arrays.copyOf() qui garantit que la classe du tableau copie est bien celle du tableau d'origine. Si tu implémentais la copie à la main par :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Object[] tabloTri =new Object[tablo.length];
    for(int k=0; k<tablo.length; k++) {
       tabloTri[k]=tablo[k];
    }

    Le retour de Object[] tri(Object[] tablo,Comparateur trieur) ne serait plus castable en Personne[], puisque de classe Object[].

    Par ailleurs, pourquoi toujours déclarer les variables en début de méthode, comme ici :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	public static Object[] tri(Object[] tablo,Comparateur trieur) 
        { 
             int i,j; 
             Object c; 
             Object[] tabloTri; 
     
    /*... */
    }


    Tu ne fais pas du C, ou je ne sais quel langage qui impose de déclarer les variables en début de méthode/fonction...

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    public static Object[] tri(Object[] tablo,Comparateur trieur) { 
             Object[] tabloTri = Arrays.copyOf(tablo,tablo.length); 
     
            for (int i=0;i< tabloTri.length;i++) 
            { 
                for(int j = i + 1; j<tabloTri.length;j++) 
                { 
     
                // utilise la fonction compare de l’objet reçu en paramètre 
                // pour comparer le contenu de deux cases du tableau 
                 if 
        (trieur.compare2(tabloTri[j],tabloTri[i])==Comparateur.INFERIEUR) 
                 { 
                      Object c = tabloTri[j]; 
                      tabloTri[j] = tabloTri[i]; 
                      tabloTri[i] = c; 
                 } 
                 else if 
        (trieur.compare2(tabloTri[j],tabloTri[i])==Comparateur.ERREUR) 
                 { 
                      return null; 
                 } 
                } 
            } 
             return tabloTri; 
        }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre habitué
    Bonjour joel.drigo et merci pour ton aide, bcp de choses dans ta réponse je vais y aller pas à pas...

    Citation Envoyé par joel.drigo Voir le message
    Salut,

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    tabTrie=(Personne[])Personne.tri(tabObj,new Personne());

    te donne une ClassCastException parce qu'un tableau d'Object (Object[]) n'est pas castable en tableau de Personne[]. Le cast n'est pas une sorte de conversion. C'est juste un moyen de faire accepter un objet d'un certain type plus générique par une variable typée dans un type plus spécifique pour permettre de manipuler l'objet via ce type spécifique. Spécifique implique qu'il étend le type plus générique. Cela implique bien sûr que l'objet soit de cette classe spécifique.



    Tout d'abord ton premier élément de réponse qui veut dire si j'ai bien compris que la Classe "Object" n'étend pas la Classe "Personne". C bien ça ?

    Puis tu dis :


    On peut caster un object de classe Personne, manipulé par le type Object en classe Personne qui étend Object :



    public class Personne {

    public static void main(String[] args) {

    Personne personne = (Personne)getPersonne();

    }

    public static Object getPersonne() {
    return new Personne();
    }

    }

    On est obligé de caster parce que le retour de getPersonne() est de type Object. Mais on peut caster parce que l'objet retourné est de classe Personne.

    Un Object[] n'est en rien un Personne[]. Personne[] n'étend pas Object[].

    Mais là quand tu dis que Personne[] n'étend pas Object[] je ne comprends pas car pour moi toute classe étend la classe Object...
    Merci de faire une retour sur ce point

    Merci à +

  4. #4
    Modérateur

    Citation Envoyé par xeron33 Voir le message

    Tout d'abord ton premier élément de réponse qui veut dire si j'ai bien compris que la Classe "Object" n'étend pas la Classe "Personne". C bien ça ?
    Oui, la classe Object n'étend pas Personne, mais c'est pas de ça que je parle.

    Citation Envoyé par xeron33 Voir le message

    Mais là quand tu dis que Personne[] n'étend pas Object[] je ne comprends pas car pour moi toute classe étend la classe Object...
    Oui, toute classe en Java étend la classe Object. Mais Object[] c'est pas Object, c'est une classe spéciale qui représente un tableau d'Object.

    Ce qu'il faut faire attention, c'est que le type d'un objet, la classe qui le définit, ce n'est pas le type d'une variable, le type par lequel on manipule l'objet référencé par la variable. Et on caste des objets (des instances de classe), pas des variables.

    On peut écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object var1 = new Personne();
    Personne var2 = (Personne)var1;


    La variable var1 est du type Object, mais l'objet référencé est du type Personne.
    On peut utiliser une variable de type Object pour référencer un objet de type Personne, parce que Personne étend Object.
    On peut caster cet objet en Personne, parce qu'il est du type Personne, pour le référencer avec une variable de type Personne.

    Si on avait une classe PersonneCelebre qui étend Personne, on pourrait écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object var1 = new PersonneCelebre();
    Personne var2 = (Personne)var1;

    Tout comme on peut référencer une instance de PersonneCelebre par une variable de type Object, parce que PersonneCelebre étend Personne qui étend Object, on peut référencer une instance de PersonneCelebre par une variable de type Personne, et on peut caster une instance de PersonneCelebre en Personne.

    Et on ne peut pas écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object var1 = new Object();
    Personne var2 = (Personne)var1; // ClassCastException parce que var1 pointe sur une instance de Object, pas sur une instance de Personne


    Avec les tableaux, c'est pareil.

    On peut écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object[] var1 = new Personne[10];
    Personne[] var2 = (Personne[])var1;

    On peut même écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object var1 = new Personne[10];
    Personne[] var2 = (Personne[])var1;

    Mais on ne peut pas écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Object[] var1 = new Object[10];
    Personne[] var2 = (Personne[])var1;


    D'ailleurs on ne peut pas écrire :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Object[] var1 = new Object[10];
    for(int i=0; i<var1.length; i++) {
        var1[i]=new Personne(); // possible parce que Personne étend Object
    }
    Personne[] var2 = (Personne[])var1; // pas possible parce que Object[], le type de ce qui est dans var1, n'étend pas Personne[],


    Alors que ça, on peut :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Object[] var1 = new Object[10];
    for(int i=0; i<var1.length; i++) {
        var1[i]=new Personne(); // possible parce que Personne étend Object, on peut donc le référencer par une variable de type Object
    }
    Personne[] var2 = new Personne[var1.length];
    for(int i=0; i<var1.length; i++) {
        var2[i]=(Personne)var1[i]; // possible parce que Personne étend Object, et c'est bien Personne le type de ce qu'il y a dans var1[i]
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre habitué
    Citation Envoyé par joel.drigo Voir le message
    Par ailleurs pourquoi passer par le type Object, ou Object[] ? Si on doit trier des Personne, pourquoi permettre de trier autre chose ? Surtout des objets de types qui possiblement ne seraient pas comparable via la méthode compare2(Object,Object) ?
    Oui en effet j'ai modifié par un type Personne[] et ça fonctionne :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
      Personne[] tabTrie2; 
      tabTrie2=new Personne[2];
      Personne[] tabTriee; 
     
    tabTriee=(Personne[])trii(tabTrie2,      
    	    	    /*	créer une instance d’une classe interne anonyme qui implémente l’interface.
    	    		// création d’une instance de classe implémentant l’interface. Classement du plus jeune au plus vieux
    	    		// l’interface Comparateur */ 
    	    		     new Comparateur() ...


    Merci pour toutes tes explications