2010-10-19 16 views
7

Recientemente me encontré con un código que no se compilaría en mi Eclipse debido al problema del "mismo borrado" (se parecía mucho al this one). Los tipos que escribieron el código me aseguraron que compila en su entorno local y su integración continua, así que jugué para emularlo.comportamiento extraño alrededor del error de compilación "mismo borrado"

Echa un vistazo a este fragmento:

package com.mycompany.playground; 

import java.util.ArrayList; 
import java.util.Collection; 

public class GenericsTest { 

    public static void main (String[] args) { 
     System.out.println(GenericsTest.doSomething(new ArrayList<A>())); 
     System.out.println(0 == GenericsTest.doSomething(new ArrayList<C>())); 
    } 

    public GenericsTest() { 
    } 

    public static String doSomething(Collection<A> listOfA) { 
     return "has done something to Collection<A>"; 
    } 

    public static Integer doSomething(Collection<C> listOfC) { 
     return 0; 
    } 

    private class A { 

    } 

    private class C { 

    } 

} 

Eclipse Helios con JDK 1.6.0_21 espacio de trabajo por defecto no se compila y se quejaba de que Método doSomething (Colección) tiene el mismo borrado doSomething (Colección) como otro método en tipo GenericsTest. Diría lo mismo sobre el otro método.

Se intentó forzar Eclipse para ejecutarlo y se vio: Excepción en el hilo "principal" java.lang.Error: Problema de compilación no resuelto: El método doSomething (Colección) en el tipo GenericsTest no es aplicable para los argumentos (ArrayList).

Ok. Eso era de esperarse. Ahora. Si entro en mi línea de comando y corro simple:

javac GenericsTest.java 

compila. Revisé 1.6.0_21 y 1.6.0_06 (el que tenían los tipos en sus entornos) y ninguno se quejó. Copié los archivos de clase a donde Eclipse los esperaba y los obligué a ejecutarlos nuevamente.

Imprime:

has done something to Collection<A> 
true 

Si se sustituye la

System.out.println(0 == GenericsTest.doSomething(new ArrayList<C>())); 

con

System.out.println(GenericsTest.doSomething(new ArrayList<C>())); 

no por ello deja compilar sin advertencias de la línea de comandos, pero dar el mismo "compilación sin resolver problema "al intentar ejecutarlo.

Dos preguntas aquí.

  • ¿Ha superado javac simplemente a los compiladores de Eclipse incorporados? Parece casi exactamente como this previously asked question, así que creo que sé la respuesta. (Por cierto, ¿cómo puedo decirle a Eclipse que use javac en su lugar?).

  • ¿Por qué javac silencio compilar lo java entonces dejará de funcionar (segundo escenario con el {0} == "pista" eliminado?

+0

El compilador de Eclipse es correcto, Sun 'javac' es incorrecto. La Especificación del lenguaje Java lo dice. Específicamente, [Sección 8.1.2 Clases genéricas y parámetros de tipo] (http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.2) cubre lo que es un tipo genérico y [ 8.4.2 Firma del método] (http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.2) cubre qué firmas causarán errores en tiempo de compilación. – Powerlord

Respuesta

0

Ambos fragmentos de código (con y sin 0 ==) trabajo para mí en mi Eclipse. Estoy usando Eclipse 3.3.2 y JDK 1.6.0_21-b07 que está configurado como "JRE alternativo" para Eclipse. Probablemente esta es la razón por la que funciona para mí.

1

La pregunta aquí es: Siempre que tenga 2 métodos con el mismo nombre, deben tener una firma diferente.La firma se considera aquí no incluye el tipo de retorno por lo que estos dos métodos no pueden ser declarados en la misma clase

int foo(A a) 
float foo(A a) 

En ti ejemplo, tiene dos métodos diferentes y con tipos de parámetros distintos (Collection<A> y Collection<C>) pero internamente, cuando el el compilador hace su magia, los genéricos son considerados Colección. Esto es lo que significa "la misma borradura".

No recuerdo ahora si todas las versiones de Java muestran este comportamiento, ya que he estado atrapado con java 5 y java 6 por demasiado.

Espero que pueda ser útil.

+0

+1. "No recuerdo ahora si todas las versiones de Java muestran este comportamiento, ya que me he quedado con java 5 y java 6 por demasiado". Los genéricos eran nuevos en Java 5, por lo que no tiene importancia antes de eso. Estoy bastante seguro de que Java 7 continuará con este comportamiento. – Powerlord

+0

De acuerdo. Por supuesto, los genéricos eran nuevos en Java 5, pero recuerdo haber visto ese "mismo borrado" antes, pero ahora no puedo reproducirlo solo con el código proporcionado por Pavel en mi entorno actual, así que me preguntaba si el comportamiento del compilador podría han cambiado de Java 5 y 6. AFAIK, en genéricos Java 5 donde algunos azúcares sintácticos alrededor del antiguo sistema de conversión, traducidos en tiempo de compilación para obtener compatibilidad binaria con Java 1.4, pero no estoy seguro de si esto es cierto a través de Java 6 y próximos 7. Pero me temo que estoy buceando en preguntas metafísicas;) – JorgeLC

1

Pavel, creo que me enfrenté con el mismo problema que usted describió.

Hoy estaba pirateando mi propio código y obtuve el mismo comportamiento diferente para los compiladores de Eclipse y Java. Sin embargo, parece que es un problema conocido del compilador.

Por favor, consulte Bug 6182950 .

Gracias!

2

Según la especificación de Java, dos métodos se deben distinguir por firma (nombre + tipos de parámetros), no por tipo de devolución. Y el código original se puede compilar debido a un error en JDK http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950 Este error se ha corregido en algunas versiones de Eclipse, es por eso que algunos de ustedes no pueden compilarlo en Eclipse. En cuanto a por qué el código compilado realmente puede funcionar, debe comprender que el lenguaje Java no es equivalente al código de bytes JVM. En el código de bytes, puede tener una gran cantidad de nombres de Java ilegales y, sí, el código de byte distingue métodos por firma, tipo de devolución y, probablemente, alguna información adicional.