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 :

covariance entre génériques


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut covariance entre génériques
    Bonjour,

    Je ne comprends pas pourquoi le compilateur Java n'assure pas la conversion suivante.

    En déclarant format() avec <K,V> (ligne commentée), je comprends que l'information générique sur K et V ne soit pas disponible dans TextOutputFormat.class.
    Par contre, avec la déclaration Class<? extends InputFormat<?,?>> (ligne non commentée), tout se passe comme si TextOutputFormat et TextOutputFormat<?,?> n'étaient pas covariants.

    Pourriez-vous m'expliquer ?
    Merci d'avance.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A<Text,NullWritable> a = ...;
    a.format(TextOutputFormat.class); // PROBLEME :  method is not applicable
    a.format((Class<? extends InputFormat<Text,NullWritable>>) TextOutputFormat.class); // ok
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Interface A<K,V> {
        /** A setter for attribute format */
        // public void format(Class<? extends InputFormat<K,V>> format);
        public void format(Class<? extends InputFormat<?,?>> format);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    java.lang.Object
      extended by org.apache.hadoop.mapreduce.OutputFormat<K,V>
          extended by org.apache.hadoop.mapreduce.lib.output.FileOutputFormat<K,V>
              extended by org.apache.hadoop.mapreduce.lib.output.TextOutputFormat<K,V>

  2. #2
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Salut,


    Je n'arrive pas à reproduire ton problème.
    Quelle est ta version de Java ?
    Comment est déclaré la classe TextOutputFormat ?


    a++

  3. #3
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci adiguba,

    Java 1..8.0_102

    Ci dessous un exemple simplifié
    A <=> Interface A<K,V>
    B <=> OutputFormat<K,V>
    C <=> TextOutputFormat<K,V>

    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
     
    public class PipoTest {
        public static class B<K,V> {}
        public static class C<K,V> extends B<K,V> {}
        public static class D extends B<String,String> {}
     
        public static class A<K,V> {
            public void foo(Class<? extends B<?,?>> arg) {}
        }
        public static void main(String[] clargs) {
            A<String,String> a = new A<>();
            a.foo(C.class);
            // The method foo(Class<? extends PipoTest.B<?,?>>) in the type PipoTest.A<String,String> is not applicable for the arguments (Class<PipoTest.C>)
     
            a.foo( (Class<? extends C<String,String>>) C.class); // valid
            a.foo(D.class); // valid
        }
     
    }

  4. #4
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    En fait, même ceci ne marche pas :

  5. #5
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Ok je pensais que TextOutputFormat était défini avec un type précis (comme "D" dans ton exemple).


    Même ce code n'est pas valide :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            a.foo( (Class<? extends C<String,String>>) C.class); // valid
    Je suppose que tu compiles avec eclipse (qui ne signale qu'un warning), mais javac sort directement une erreur : incompatible types: Class<C> cannot be converted to Class<? extends C<String,String>>



    Le "truc" c'est que B.class est de type Class<B> et non pas Class<B<?,?>>, et il y a bien une différence entre les deux et ils ne sont pas compatible même s'ils peuvent sembler similaire :
    • Class<B<?,?>> correspond à une classe B dont on ne connait pas les types paramétrés.
    • Class<B> correspond au raw-type, c'est à dire sans aucun type paramétré.



    Donc dans ton cas il faudrait plutôt déclarer la méthode comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public void foo(Class<? extends B> arg) {}
    Mais... c'est un usage "unsafe" qui génèrera un warning.



    D'où ma nouvelle question : à quoi cela doit-il te servir ?
    Que va tu faire de cet objet Class ?


    a++

  6. #6
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci bcp pour l'explication !

    Cela me sert à vérifier que les paramètres génériques du B que je vais assigner à A<K,V> sont bien cohérents avec K et V.
    En particulier si une autre méthode de B renvoie des K et des V, je veux être sur de les manipuler en tant que K et V dans la classe A.

    Maintenant, je suis en train de réaliser que les setters auxquels je communique ces classes sont declarés avec des raw types.
    Mais quand bien même, n'est ce pas la bonne approche pour effectuer les vérifications dont je parle au compile-time ?

  7. #7
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Mais concrètement : comment tu te sert de l'argument "Class" de la méthode foo() ?

    Parce que si tu utilises des raw-types ou des <?> tu ne vérifies rien du tout.
    De même que si tu utilises un type au lieu d'une instance : le fait de passer un OutputFormat.class ne te permet pas d'assurer quoi que ce soit.


    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 41
    Dernier message: 30/03/2010, 16h42
  2. tri générique entre objets
    Par cashmoney dans le forum Langage
    Réponses: 31
    Dernier message: 12/03/2009, 14h03
  3. Réponses: 3
    Dernier message: 07/05/2008, 15h57

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