2009-07-24 17 views
7

Tenemos algunas pruebas unitarias que se compilan y ejecutan bien en Eclipse 3.4, pero cuando intentamos compilarlas usando javac, falla. He logrado reducir el código a algo pequeño y autónomo, por lo que no tiene dependencias externas. El código en sí no tiene mucho sentido porque es todo fuera de contexto, pero eso no importa - sólo hay que averiguar por qué javac no le gusta esto:¿Por qué Eclipse compila esto, pero javac no?

public class Test { 

    public void test() { 
     matchOn(someMatcher().with(anotherMatcher())); 
    } 

    void matchOn(SubMatcher matcher) {} 

    SubMatcher someMatcher() { 
     return new SubMatcher(); 
    } 

    Matcher anotherMatcher() { 
     return null; 
    } 
} 

interface Matcher <U, T> {} 

class BaseMatcher implements Matcher { 
    public BaseMatcher with(Matcher<?,?> matcher) { 
     return this; 
    } 
} 

class SubMatcher extends BaseMatcher { 
    @Override 
    public SubMatcher with(Matcher matcher) { 
     return this; 
    } 
} 

He tratado con JDK 1.5.0_10 y 1.6.0_13, con el mismo resultado:

Test.java:6: matchOn(test.SubMatcher) in test.Test cannot be applied to (test.BaseMatcher) 
       matchOn(someMatcher().with(anotherMatcher())); 
       ^
1 error 

creo que esto es perfectamente válido de Java. El método SubMatcher.with() devuelve un tipo más específico que BaseMatcher.with(), pero el compilador parece pensar que el tipo de devolución es BaseMatcher. Sin embargo, es posible que el compilador de Eclipse esté permitiendo incorrectamente algo que no debería ser.

¿Alguna idea?

+1

Puedo reproducir este error de compilación con jdk 1.6 en Linux. Parece que los tipos de retorno covariantes introducidos con Java 1.5 no funcionan correctamente en este ejemplo. – Mnementh

Respuesta

7

en BaseMatcher es necesario que especifique los parámetros de tipo:

public SubMatcher with(Matcher<?, ?> matcher) { 

con el fin de permitir que javac para que coincida con su método de with

PS

en mi humilde opinión es un error del compilador Eclipse

+0

Ach, no puedo creer que no haya detectado ... – skaffman

+0

Tanto usted como Greg obtuvieron la respuesta, pero tengo que darle el premio a alguien, y fuiste un poco más rápido ... – skaffman

0

Compruebe con qué jre o jdk está compilando tanto en Eclipse como en el terminal. Tal vez podría ser el problema de versión.

+0

Eclipse está utilizando el 1.5.0_10 JRE, el mismo que el javac que estoy intentando. – skaffman

+0

Eclipse tiene su propio compilador, es decir, no usa javac – robinr

0

Funciona para mí:

 
$ java -version 
openjdk version "1.7.0-internal" 
OpenJDK Runtime Environment (build 1.7.0-internal-****-2009_07_23_10_21-b00) 
OpenJDK 64-Bit Server VM (build 16.0-b06, mixed mode) 
$ javac -XDrawDiagnostics Test.java 
$ 

Recuerdo vagamente un informe de errores, pero no puedo darle un enlace ahora.

7

lo hice construir con éxito mediante la adición de <?,?>-Matcher en SubMatcher.with:

class SubMatcher extends BaseMatcher { 
    @Override 
    public SubMatcher with(Matcher<?,?> matcher) { 
     return this; 
    } 
} 

Sin esto, la firma del método es diferente de la base. Me pregunto si hay un error en la comprobación @Override que no se da cuenta de esto.

+3

Esta es una situación interesante. Podría argumentar que javac tiene la culpa aquí, porque está permitida la anotación @Override, pero luego usa el método de la subclase en lugar de la anulada. Esto es inconsistente, la anotación está ahí para evitar este tipo de problema. La pregunta es si un método con un parámetro de tipo sin formato puede anular un método de superclase del mismo tipo con skaffman

Cuestiones relacionadas