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.
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.
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é.
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
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.