Ho incontrato un problema in Java Generics in cui lo stesso codice si compilerà e funzionerà correttamente in Java 6, ma non riuscirà a compilare a causa della stessa cancellazione in Java 5. ho un TestErasure.java di file che ha un metodo di overload, chiamato "metodo":Differente comportamento tra Java 5 e 6 quando si sovraccaricano metodi generici
import java.util.ArrayList;
import java.util.List;
public class TestErasure {
public static Object method(List<Object> list) {
System.out.println("method(List<Object> list)");
return null;
}
public static String method(List<String> list) {
System.out.println("method(List<String> list)");
return null;
}
public static void main(String[] args) {
method(new ArrayList<Object>());
method(new ArrayList<String>());
}
}
In Java 5, ottengo l'errore di compilazione atteso, affermando che la cancellazione di "metodo" è lo stesso:
$ javac -version
javac 1.5.0_19
$ javac TestErasure.java
TestErasure.java:10: name clash: method(java.util.List<java.lang.String>) and method(java.util.List<java.lang.Object>) have the same erasure
public static String method(List<String> list) {
^
TestErasure.java:17: method(java.util.List<java.lang.Object>) in TestErasure cannot be applied to (java.util.ArrayList<java.lang.String>)
method(new ArrayList<String>());
^
2 errors
Tuttavia, Java 6 è in grado di compilare ed eseguire questo stesso codice.
$ javac -version
javac 1.6.0_16
$ javac TestErasure.java
$ java TestErasure
method(List<Object> list)
method(List<String> list)
In base alla mia attuale comprensione di cancellature (grazie a Jon Skeet e Angelika Langer), in realtà ho atteso l'errore di compilazione come gettata da Java 5 (a meno che qualcosa è cambiato nel modo in cui ha gestito Java generici - che non riesco a trovare su le note di rilascio di Java 6). Infatti, se modifico il tipo di ritorno di uno dei metodi di overload:
public static Object method(List<Object> list) ...
public static Object method(List<String> list) ...
Java 6 non riesce inoltre a compilare causa delle stesse cancellature:
$ javac TestErasure.java TestErasure.java:5: name clash: method(java.util.List<java.lang.Object>) and method(java.util.List<java.lang.String>) have the same erasure
public static Object method(List<Object> list) {
^
TestErasure.java:10: name clash: method(java.util.List<java.lang.String>) and method(java.util.List<java.lang.Object>) have the same erasure
public static Object method(List<String> list) {
^
2 errors
Sembra come se il tipo di ritorno in Java 6 influenza in qualche modo la selezione di quale metodo di overload usare?
Qualcuno può far luce sul motivo per cui il primo esempio funziona in Java 6 - sembra andare contro la gestione dichiarata di metodi generici sovraccaricati?
Maggiori informazioni:
suggerimento di Per David, l'esempio originale, rispettato da javac 1.6, verrà eseguito sotto la Java 1.5:
$ javac -target 1.5 TestErasure.java
$ java -version
java version "1.5.0_19"
$ java TestErasure
method(List<Object> list)
method(List<String> list)
l'(cancellato) tipo di ritorno fa parte del m firma ethod in tutte le versioni di Java. –
Il tipo restituito fa parte del descrittore del metodo, ma non della firma del metodo, corretto? http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#What%20is%20a%20method%20signature? –
@ Tom - Credo che tu stia sbagliando - "Definizione: due dei componenti di una dichiarazione di metodo comprendono la firma del metodo, il nome del metodo e i tipi di parametro." Da http://java.sun.com/docs/books/tutorial/java/javaOO/methods.html. La firma del metodo deve essere univoca perché l'overloading del metodo funzioni e non si basano sul tipo restituito (almeno per Java). – weiji