Ça compile ? L’hideux soleil caché n’est pas du même avis.

Allez, je tente un premier article sous forme de quiz :

  • A votre avis, est-ce que le code suivant compile ?
  • Pourquoi ?
  • Si oui, que se passe-t’il à l’exécution ?
  • Si non, comment corriger le problème ?

1
2
3
4
5
6
7
8
9
public class GenericTest {
    public static void main(String[] args) {
        int magicValue = magicMethod();
        System.out.println(magicValue);
    }
    public static <T> T magicMethod() {
        return null;
    }
}

J’attend vos réponses en commentaires !!

Bien entendu, essayez de répondre sans tricher (j’ai un détecteur anti cheat ;-)).

VN:R_U [1.9.22_1171]
Rating: +1 (from 1 vote)
Share

À propos de Pierre-Yves Ricau

Découvrez mon cv dynamique en ligne !
Ce contenu a été publié dans Quiz, avec comme mot(s)-clef(s) , , , . Vous pouvez le mettre en favoris avec ce permalien.

19 réponses à Ça compile ? L’hideux soleil caché n’est pas du même avis.

  1. jsoula@excilys.com dit :

    Le code compile.
    Par contrat au Runtime, on a une NullPointerException à cause de l’autoboxing réalisé ligne 3.
    Une des corrections au problème est de mettre magicValue en Integer.

    SCJP POWER!!!!

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  2. Tu tiens une partie de la réponse Jérémy ;-) . Et si tu tentais de compiler le code avec Javac plutôt qu’avec ton IDE favori :-P ?

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  3. J’ai copié/collé le code dans Intellij, et j’ai été surpris de voir qu’il n’affichait pas d’erreur. Mon compilateur cérébral n’arrive pas à détecter quel type serait utilisé pour T au runtime, il me sort donc une erreur. Et quand bien même le code compilerait et s’exécuterait, je pense qu’il y aurait une NPE due à l’assignation de null dans l’int.

    On pourrait forcer le type à utiliser avec un int magicValue = magicMethod<Integer>(); mais le langage ne le permet pas. Je propose donc de passer un paramètre bidon de type T à cette méthode, et de remplacer int par Integer. javac/java (les vrais cette fois !) me confirment que ça fonctionne :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class GenericTest {
        public static void main(String[] args) {
            Integer magicValue = magicMethod(Integer.valueOf(1337));
            System.out.println(magicValue);
        }
        public static <T> T magicMethod(T foo) {
            return null;
        }
    }
    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • jsoula@excilys.com dit :

      Bastien: ce code compile aussi (au moins chez moi ;)):

      
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      public class GenericTest {
          public static void main(String[] args) {
              Integer magicValue = magicMethod();
              System.out.println(magicValue);
          }
          public static <T> T magicMethod() {
              return null;
          }
      }
      VN:R_U [1.9.22_1171]
      Rating: 0 (from 0 votes)
      • Lol, Bastien aime la complexité :-)

        Effectivement, remplacer int par Integer fait que le code compile et s’exécute sans exception sur tous les compilos.

        @Bastien :

        On pourrait forcer le type à utiliser avec un int magicValue = magicMethod<Integer>(); mais le langage ne le permet pas.

        Hey, mais t’as eu ta SCJP dans une pochette surprise ? :-P C’est tout à fait possible en mettant les generics au bon endroit :

        1
        int magicValue = GenericTest.<Integer>magicMethod();

        Oh magie, ça compile ! Avec l’IDE, mais surtout avec javac ;-)

        VN:R_U [1.9.22_1171]
        Rating: 0 (from 0 votes)
  4. mpicque@excilys.com dit :

    Pour être sur de n’avoir aucune erreur à la compilation et au runtime quelque soit le compilateur, il faut utiliser le code suivant :

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class GenericTest {
        public static void main(String[] args) {
            Integer magicValue = GenericTest.<Integer> magicMethod();
            System.out.println(magicValue);
        }

        public static <T> T magicMethod() {
            return null;
        }
    }
    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • L’exemple de Jeremy (plus haut) fonctionne aussi très bien avec tous les compilateurs, ainsi qu’au runtime : Integer magicValue = magicMethod(); ;-)

      VN:R_U [1.9.22_1171]
      Rating: 0 (from 0 votes)
      • jsoula@excilys.com dit :

        Ouais mais ce code la ne marche pas

        
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        public class GenericTest {
            public static void main(String[] args) {
                Integer magicValue = anotherMagicMethod();
                System.out.println(magicValue);
            }

            private static <U> U anotherMagicMethod() {
                U magicValue = magicMethod();//Compile pas avec jdk sun
                return magicValue;
            }

            public static <T> T magicMethod() {
                return null;
            }
        }

        Il faut utiliser l’astuce donnée par Mister Picque

        VN:R_U [1.9.22_1171]
        Rating: 0 (from 0 votes)
        • Woah, génial, j’avais pas pensé à ça :-O

          Effectivement, en précisant le type ça fonctionne. Mais je me demande si c’est la même raison qui cause l’erreur avec int et l’erreur avec U …

          Du coup, on obtient :

          
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          public class GenericTest {
              public static void main(String[] args) {
                  Integer magicValue = anotherMagicMethod();
                  System.out.println(magicValue);
              }
              private static <U> U anotherMagicMethod() {
                  U magicValue = GenericTest.<U> magicMethod(); // Compile
                  return magicValue;
              }
              public static <T> T magicMethod() {
                  return null;
              }
          }
          VN:R_U [1.9.22_1171]
          Rating: 0 (from 0 votes)
  5. mpicque@excilys.com dit :

    ça devient de plus en plus compliqué comme cas.

    Et en plus on peut toujours ajouter des niveaux !!!

    On va peut être s’arrêter là non ? ;-)

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  6. jsoula@excilys.com dit :

    Pour conclure, j’ai surfé avec ces 2 posts pour essayer de voir ce qui se passe à l’interieur du soleil hideux:
    Post 1
    Post 2

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  7. jsoula@excilys.com dit :

    L’astuce marche pour les méthodes statiques. Mais qu’en est-il des autres? Quelqu’un a une idée pour compiler ca:

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class GenericTest {
        public static void main(String[] args) {
            Integer magicValue = new GenericTest().anotherMagicMethod();
            System.out.println(magicValue);
        }

        private  <U> U anotherMagicMethod() {
            U magicValue = magicMethod();//Compile pas avec jdk sun
            return magicValue;
        }

        public  <T> T magicMethod() {
            return null;
        }
    }
    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • Héhé, il suffit d’appliquer tout à fait la même technique, mais avec this : U magicValue = this.<U>magicMethod();

      
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      public class GenericTest {
          public static void main(String[] args) {
              Integer magicValue = new GenericTest().anotherMagicMethod();
              System.out.println(magicValue);
          }

          private  <U> U anotherMagicMethod() {
              U magicValue = this.<U>magicMethod();//Compile
              return magicValue;
          }

          public  <T> T magicMethod() {
              return null;
          }
      }
      VN:R_U [1.9.22_1171]
      Rating: 0 (from 0 votes)
  8. jsoula@excilys.com dit :

    Encore une question: Dans ma grande naïveté, je croyais qu’eclipse utilisait le compilateur que l’on configurait dans les préférences. D’où est-ce que vient la différence? Eclipse utilise son propre compilateur?

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • Ouaip. C’est un compilateur incrémental, qui lui permet de faire des compilations partielles. Ce qui explique par exemple pourquoi ton code devient rouge / propose l’autocomplétion au fur et à mesure que tu le tapes, sans sauvegarder, et alors que la syntaxe n’est pas forcément juste. Passer par une compil classique prendrait trop de temps.

      Tu le vois aussi pour le projet Lombok, qui a du développer une version javac, une version eclipse, etc…

      Après, je ne suis pas expert des détails et je dis ptet des bêtises sur certains points. Corrigez-moi si besoin !

      VN:R_U [1.9.22_1171]
      Rating: 0 (from 0 votes)

Laisser un commentaire