2013-04-18 2 views
2

Мне было интересно, почему следующий код не может использовать информацию типа обобщенного типа для правильного поиска наиболее специфичной перегрузки метода, вместо этого он всегда использует применимый метод ко всем потенциальным общим параметрам. Нет ли способа включить общий тип параметра во время компиляции, чтобы избежать неприятного отражения во время выполнения?Java почему перегрузка метода из общего типа не может быть определена во время компиляции

import org.junit.Assert; 
import org.junit.Test; 

import java.util.ArrayList; 
import java.util.List; 

public class Temp { 
    class A<T> { 
     T x; 
     A(T x) { 
      this.x = x; 
     } 
     String bar = foo(x); 

     private String foo(Integer i) { 
      return "Int"; 
     } 
     private String foo(String i) { 
      return "String"; 
     } 
     private <T> String foo(List<T> l) { 
      return "List"; 
     } 
     private <T> String foo(T v) { 
      return "Value"; 
     } 
    } 

    @Test 
    public void IntTest() { 
     Assert.assertEquals(new A<Integer>(1).bar, "Int"); 
    } 
    @Test 
    public void StringTest() { 
     Assert.assertEquals(new A<String>("A").bar, "String"); 
    } 
    @Test 
    public void ListTest() { 
     Assert.assertEquals(new A<List<String>>(new ArrayList<String>()).bar, "List"); 
    } 
    @Test 
    public void LongTest() { 
     Assert.assertEquals(new A<Long>(1L).bar, "Value"); 
    } 
} 
+0

Возможный дубликат [Метод имеет такое же стирание, как и другой метод в типе] (http://stackoverflow.com/questions/1998544/method-has-the-same-erasure-as-another-method-in-type) –

+0

Типы не имеют такого же стирания, хотя - Integer, String, List - все разные стирания. – Woodz

ответ

4

Это потому, что компилятор должен создать другой класс A для каждого типа, который используется для T (потому что инициализатор A.bar должен был бы вызов другого метода). Было принято решение создать только один класс. Это отличается от, например, C++, где компилятор генерирует новый тип для всех используемых параметров типа.

Иными словами, скомпилированный код для типа A<String> будет отличаться от типа A<Integer>, но после компиляции есть только тип A.

3

Это побочные дженерики удаляются во время компиляции. Существует концепция стирания, которая удаляет весь код генериков во время компиляции, заменяет его типом. Таким образом, java не будет знать методы дженериков во время выполнения.

EDIT:

Проверить эту ссылку также: http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#cannotOverload

+1

Вопрос в том, почему это невозможно сделать во время компиляции, поэтому удаляемая информация в то же время не имеет смысла, поскольку объяснение. Это связано с тем, что Java-дженерики не являются механизмом шаблонов. В коде примера есть только один вызов 'foo'. Не было выбрано переопределение на основе типа времени выполнения. –

+0

Итак, чтобы уточнить, это связано с тем, что генерические файлы удаляются во время компиляции. ПЕРЕД ПЕРВОЙ способ выбора перегрузки выбрано? – Woodz

+0

@Woodz Принятый ответ для [вопроса, который я обозначил как дубликат) (http://stackoverflow.com/questions/1998544/method-has-the-same-erasure-as-another-method-in-type) объясняет это очень ясно. –