Различное поведение между Java 5 и 6 при перегрузке универсальных методов - PullRequest
18 голосов
/ 17 сентября 2009

Я столкнулся с проблемой в Generics Java, в которой тот же код будет компилироваться и нормально работать в Java 6, но не удастся компилировать из-за того же стирания в Java 5. У меня есть файл TestErasure.java, который имеет перегруженный метод с именем «method»:

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>()); 
 }
}

В Java 5 я получаю ожидаемую ошибку компиляции, утверждая, что стирание «метода» одинаково:

$ 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

Однако Java 6 может скомпилировать и запустить этот же код.

$ javac -version
javac 1.6.0_16
$ javac TestErasure.java
$ java TestErasure
method(List<Object> list)
method(List<String> list)

Основываясь на моем текущем понимании стираний (благодаря Jon Skeet и Angelika Langer ), я фактически ожидал ошибку компиляции, выданную Java 5 (если что-то не изменилось в том, как Java обрабатывается Generics - что я не могу найти в заметках о выпуске Java 6). Фактически, если я изменю тип возвращаемого значения одного из перегруженных методов:

public static Object method(List<Object> list) ...
public static Object method(List<String> list) ...

Java 6 также не может скомпилироваться из-за того же удаления:

$ 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

Похоже, что возвращаемый тип в Java 6 как-то влияет на выбор того, какой перегруженный метод использовать?

Может кто-то пролить свет на то, почему первый пример работает в Java 6 - похоже, он идет вразрез с заявленной обработкой перегруженных обобщенных методов?

Подробнее:

Согласно предложению Дэвида, оригинальный пример, выполненный javac 1.6, будет работать под 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)

1 Ответ

8 голосов
/ 17 сентября 2009

Нашли эти ошибки на Sun, которые, я думаю, вы описываете:

http://bugs.sun.com/view_bug.do?bug_id=6182950
http://bugs.sun.com/view_bug.do?bug_id=6730568

...