2010-07-15 22 views
7

Duplicar posible:
Is this valid Java?Característica o error: ¿Por qué compila este código de Java?

que se sorprendió al descubrir la clase de Java compila a continuación. Tiene varias método, con el mismo nombre, el número de argumentos y siguientes tipos Tipo-de borrado de argumento. Sin embargo, compila y funciona como se esperaba, en Windows utilizando varias versiones del compilador Sun JDK 1.6. Así que si esto es un error que ha sido alrededor de las edades ....

También ha compilado con numerosas versiones de Eclipse, pero no del compilador con el compilador que se incluye con Eclipse 3.6

Además código de llamada funciona como se esperaba, es decir. no hay errores sobre métodos ambiguos en el código de llamada.

Si iterar sobre los métodos devueltos por ErasureExample.class.getMethods() que están todos presentes .....

De acuerdo con el JLS sería ilegal si los métodos tienen "anulan equivalente" firmas - estrictamente no lo hacen, ya que ninguno de Colección, Colección Colección ni son equivalentes anulación .... si ese es el caso, el Eclipse está mal, JDK correcta ...

Característica o error? ¿Debería compilarse?

/** 
* Demonstrates that a class with methods that differ only by return type can exist. 
* Section 8.4 of the JLS suggests this is an error IFF the methods had 
* override equivalent signatures, which they dont'' 
* 
* 
* From JLS 8.4... 

* It is a compile-time error for the body of a class to declare as members two methods 
* with override-equivalent signatures (§8.4.2) (name, number of parameters, and types 
* of any parameters). 
* 
* Should it compile? 
*/ 
public class ErasureExample { 
    // note the single Collection<Integer> argument... 
    public static int[] asArray(Collection<Integer> vals) { 
     if (vals == null) 
     return null; 

     int idx = 0; 
     int[] arr = new int[vals.size()]; 
     for (Integer i : vals) { 
     arr[idx] = i==null? 0 : i.intValue(); 
     idx++; 
     } 
     return arr; 
    } 

    // same method name as above, type differs only by generics.... surely this violates 8.4 of JLS... 
    public static long[] asArray(Collection<Long> vals) { 
     if (vals == null) 
     return null; 

     int idx = 0; 
     long[] arr = new long[vals.size()]; 
     for (Long i : vals) { 
     arr[idx] = i==null? 0 : i.longValue(); 
     idx++; 
     } 
     return arr; 
    } 

    // same method name as above, type differs only by generics.... surely this violates 8.4 of JLS... 
    public static boolean[] asArray(Collection<Boolean> vals) { 
     if (vals == null) 
     return null; 

     int idx = 0; 
     boolean[] arr = new boolean[vals.size()]; 
     for (Boolean b : vals) { 
     arr[idx] = b==null? false : b.booleanValue(); 
     idx++; 
     } 
     return arr; 
    } 

} 

Respuesta

-3

Estos métodos no tienen las mismas firmas en absoluto. Diferentes valores de retorno y diferentes tipos de parámetros. Sí, de hecho, los genéricos hacen una gran diferencia. Todo se ve bien aquí.

+7

corrección: el valor de retorno no es parte de la firma – schar

+5

En realidad, en el nivel de bytecode, los descriptores de método también contienen el tipo de retorno, y se pueden usar para diferenciarlos. El compilador veces puede tomar ventaja de que, mediante la comprobación del tipo de la variable se guarda el resultado en, ya que el compilador puede decir qué método debe ser llamado, y en el código de bytes es sólo método llamado la instrucción' con el descriptor este-y- ese'. No es exactamente correcto, de acuerdo con las especificaciones, pero el compilador lo permite por ahora. Aparentemente en Java 7 podrían cambiar esto. –

+1

Después de jugar un poco con este código, creo que la explicación de Andrei Fierbinteanu es la más convincente. Parece que no hay problemas prácticos con la compilación de métodos con firma idéntica, ya que las llamadas en el bytecode se basan en identificadores numéricos únicos de los métodos. Algunos compiladores aprovechan el hecho de que tienen información genérica para que esto sea posible. Esto causa problemas. Véase, por ejemplo lo que sucede con la reflexión: ErasureExample.class.getDeclaredMethod ("asArray", Collection.class) devuelve el primer método en el código fuente (es decir, reordenar el código cambia las cosas) –

2

El compilador es suficiente para eliminar la ambigüedad de los métodos en tiempo de compilación inteligente, aunque al final se lleva a cabo el tipo de borrado. El objetivo de la parametrización de los genéricos es proporcionar una verificación de seguridad del tipo de tiempo de compilación, el borrado de tipos es solo un detalle de la implementación.

Cuestiones relacionadas