Java 8: La référence à est ambiguë

Est-ce que quelqu’un comprend pourquoi le code suivant comstackra correctement Java 7 et inférieur, mais échoue avec Java 8.

public static void main(Ssortingng[] args) throws Exception { put(get("hello")); } public static  R get(Ssortingng d) { return (R)d; } public static void put(Object o) { System.err.println("Object " + o); } public static void put(CharSequence c) { System.err.println("CharSequence " + c); } public static void put(char[] c) { System.err.println("char[] " + c); } 

La méthode get a un type de retour générique. Dans JDK 7 et inférieur, cela comstack bien et la méthode put avec le paramètre Object est choisie. Dans JDK 8, cela ne peut pas être compilé, indiquant que la méthode put est ambiguë.

Apparemment, JDK 8 saute la méthode Object-parameter et trouve les deux dernières méthodes sub-Object-paramètre et se plaint (c’est-à-dire que si vous ajoutez une autre méthode put avec un autre type de paramètre, le compilateur basculera et se plaindra du deux méthodes)

Cela ressemble à un bug.

    Votre problème est un effet secondaire de l’ inférence généralisée de type cible , une amélioration de Java 8.

    Qu’est-ce que l’inférence de type cible?

    Prenons votre exemple de méthode,

     public static  R get(Ssortingng d) { return (R)d; } 

    Maintenant, dans la méthode ci-dessus, le paramètre générique R ne peut pas être résolu par le compilateur car il n’y a pas de paramètre avec R

    Ils ont donc introduit un concept appelé Target-type Inference , qui permet de déduire le paramètre en fonction du paramètre d’affectation.

    Donc, si vous le faites,

      Ssortingng str = get("something"); // R is inferred as Ssortingng here Number num = get("something"); // R is inferred as Number here 

    Cela fonctionne bien dans Java 7. Mais ce qui suit ne fonctionne pas ,

     put(get("something"); static void Put(Ssortingng str) {} //put method 

    Parce que l’inférence de type n’a fonctionné que pour les affectations directes.

    S’il n’y a pas d’affectation directe, le type générique a été déduit en tant Object .

    Ainsi, lorsque vous avez compilé le code avec Java 7, votre méthode put(Object) été appelée sans aucun problème.

    Ce qu’ils ont fait dans Java 8

    Ils ont amélioré l’ inférence de type pour déduire le type des appels de méthode et des appels de méthode chaînés

    Plus de détails à leur sujet ici et ici

    Alors maintenant, vous pouvez appeler directement put(get("something")) et le type générique sera déduit en fonction du paramètre de la méthode put() .

    Mais comme vous le savez, les méthodes, put(Charsequence) et put(char[]) correspondent aux arguments. Il y a donc l’ambiguïté.

    Réparer?

    Dites simplement au compilateur ce que vous voulez,

     put(TestClass.get("hello")); // This will call the put(CharSequence) method. 

    On dirait que c’est une incompatibilité connue.

    Voir la section “Zone: Outils / javac” de cet article. Et ce bug .

    Synopsis

    Le code suivant qui a compilé, avec des avertissements, dans JDK 7 ne sera pas compilé dans JDK 8:

     import java.util.List; class SampleClass { static class Baz { public static List> sampleMethod(Baz param) { return null; } } private static void bar(Baz arg) { Baz element = Baz.sampleMethod(arg).get(0); } } 

    La compilation de ce code dans JDK 8 génère l’erreur suivante:

     SampleClass.java:12: error:incompatible types: Object cannot be converted to Baz Baz element = Baz.sampleMethod(arg).get(0); Note: SampleClass.java uses unchecked or unsafe operations. Note: Recomstack with -Xlint:unchecked for details. 1 error 

    Dans cet exemple, un type brut est en train d’être transmis à la méthode sampleMethod (Baz), applicable par sous-typage (voir JLS, Java SE 7 Edition, section 15.12.2.2).

    Une conversion non contrôlée est nécessaire pour que la méthode soit applicable. Par conséquent, son type de retour est effacé (voir JLS, Java SE 7 Edition, section 15.12.2.6). Dans ce cas, le type de retour de sampleMethod (Baz) est java.util.List au lieu de java.util.List> et le type de retour de get (int) est Object, qui n’est pas compatible avec une affectation de Baz.