2010-10-19 13 views
7

Recentemente sono incappato in un pezzo di codice che non sarebbe stato compilato in Eclipse a causa della "stessa cancellazione" (sembrava molto simile a this one). I ragazzi che hanno scritto il codice mi hanno assicurato che compila nel loro ambiente locale e la loro continua integrazione e così ho giocato insieme per emularlo.comportamento strano attorno all'errore di compilazione "same erasure"

Date un'occhiata a questo frammento:

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 1.6.0_21 JDK come spazio di lavoro di default non sarebbe compilarlo e si lamentava che il metodo doSomething (Collection) ha la stessa cancellazione doSomething (Collection) come un altro metodo nel tipo GenericsTest. Direbbe lo stesso per l'altro metodo.

Tentativo di forzare Eclipse per eseguirlo e visto: Eccezione nel thread "main" java.lang.Error: problema di compilazione non risolto: il metodo doSomething (Collection) nel tipo GenericsTest non è applicabile per gli argomenti (ArrayList).

Ok. Era prevedibile. Adesso. Se vado nella mia riga di comando ed eseguo semplice:

javac GenericsTest.java 

compila. Ho controllato 1.6.0_21 e 1.6.0_06 (quello che i ragazzi avevano nel loro ambiente) e nessuno dei due si è lamentato. Ho copiato i file di classe su dove Eclipse li aspettava e l'ho obbligato a eseguirlo di nuovo.

Esso stampa:

has done something to Collection<A> 
true 

Se si sostituisce la

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

con

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

sarebbe ancora compilare senza avvertimenti da riga di comando, ma dare lo stesso "compilation non risolti problema "durante il tentativo di eseguirlo.

Due domande qui.

  • javac ha semplicemente superato in astuzia il compilatore Eclipse incorporato? Sembra quasi esattamente come this previously asked question quindi credo di conoscere la risposta. (a proposito, come posso dire ad Eclipse di usare javac?).

  • Perché sarebbe javac silenziosamente compilare quello che java poi non riuscire a correre (secondo scenario con {0} == "suggerimento" rimosso?

+0

Il compilatore di Eclipse è corretto, Sun 'javac' è errato. Lo dice la specifica del linguaggio Java. In particolare, [Sezione 8.1.2 Classi generiche e Parametri del tipo] (http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.2) copre cosa sia un tipo generico e [ 8.4.2 Firma del metodo] (http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.2) illustra quali firme causeranno errori in fase di compilazione. – Powerlord

risposta

0

Entrambi i frammenti di codice (con e senza 0 ==) lavoro per me nel mio Eclipse Sto usando Eclipse 3.3.2 e JDK 1.6.0_21-b07 che è configurato come "Alternative JRE" per Eclipse.Probabilmente questo è il motivo per cui funziona per me

1

La domanda qui è: Ogni volta che hai 2 metodi con lo stesso nome, devono avere una firma diversa.La firma qui considerato non include tipo di ritorno in modo che questi due metodi non possono essere dichiarate nella stessa classe

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

In te ad esempio, ci sono due metodi differenti con tipi di parametri distinti (Collection<A> e Collection<C>) ma internamente, quando la il compilatore fa la sua magia, i generici sono considerati collezione. Questo è ciò che significa "stessa cancellazione".

Non ricordo in questo momento se tutte le versioni java mostrano questo comportamento, dal momento che sono rimasto bloccato con java 5 e java 6 per troppo.

Spero che possa essere utile.

+0

+1. "Non ricordo in questo momento se tutte le versioni Java mostrano questo comportamento, dal momento che sono rimasto bloccato con java 5 e java 6 per troppo". I generici erano nuovi in ​​Java 5, quindi non importa prima. Sono abbastanza sicuro che Java 7 continuerà con questo comportamento. – Powerlord

+0

Accetto. Ovviamente i generici erano nuovi in ​​Java 5, ma ricordo di aver visto "la stessa cancellazione" prima, ma ora non riesco a riprodurlo da solo con il codice fornito da Pavel nel mio ambiente corrente, quindi mi chiedevo se il comportamento del compilatore potesse sono passati da Java 5 e 6. AFAIK, in Java 5 generici in cui un po 'di zucchero sintattico attorno al vecchio cast system, tradotto in fase di compilazione per ottenere la compatibilità binaria Java 1.4, ma non sono sicuro se questo è vero attraverso Java 6 e imminente 7. Ma temo di immergermi in domande metafisiche;) – JorgeLC

1

Pavel, penso di aver affrontato lo stesso problema che hai descritto.

Oggi stavo tagliando il mio codice e ho ottenuto lo stesso comportamento per i compilatori di Eclipse e Java. Tuttavia, sembra che sia un problema noto del compilatore.

Si prega di fare riferimento a Bug 6182950 .

Grazie!

2

In base alle specifiche Java, è necessario distinguere due metodi per firma (nome + tipi di parametro), non per tipo di ritorno. E il codice originale può essere compilato a causa di un bug in JDK http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950 Questo bug è stato corretto in alcune versioni di Eclipse, ecco perché alcuni di voi non possono essere compilati in Eclipse. Per quanto riguarda il motivo per cui il codice compilato può effettivamente funzionare, è necessario comprendere che il linguaggio Java non è equivalente al codice byte JVM. Nel codice byte è possibile avere un sacco di nomi Java illegali e sì, il codice byte distingue i metodi per firma, tipo di ritorno e probabilmente alcune informazioni aggiuntive.