2011-11-18 8 views
5

He descubierto los siguientes problemas con genéricos. Considere la interfaz genéricaAccediendo a argumentos de tipo de tipos genéricos utilizados en typebounds

public interface A<X> { 
    X get(); 
    void doStuff(X x); 
} 

Ahora, vamos a suponer la siguiente definición del método:

public <T extends A<?>> void foo(T t) { 
    bar(t); 
} 

Debido al carácter comodín, la información de tipo para el tipo de retorno de get() es insuficiente. Por lo tanto, tengo que delegar a otro método que "se une" este comodín para una variable de tipo fresco:

private <X> void bar(A<X> t) { 
    X x = t.get(); 
    t.doStuff(x); 
} 

No se permite la invocación de bar() en foo, el compilador genera el mensaje de error:

la barra de método (a) en el ensayo de tipo no es aplicable para los argumentos (T)

sin embargo, si cambio de la foo() para

public <T extends A<?>> void foo(T t) { 
    A<?> u = t; // No explicit cast required, no "unchecked" warning! 
    bar(u); 
} 

funciona. ¿Por qué? ¿Es esto un error del compilador? Cualquier comentario sobre esto sería muy apreciado.

Notas:

  • La razón por la que no se limitan a declarar el método foo foo como nula (a), que en realidad estoy usando el interesection cota de tipo superior (&).
  • La razón por la que no declaro X como una variable de tipo en foo() es que realmente tengo el problema a nivel de clase y no quiero aumentar innecesariamente el número de parámetros de tipo de esta clase.
+0

¿Está utilizando el indicador de compilador -Xlint? Si no, intente compilar con ese –

+0

No cambia nada ... – misberner

+0

Estoy de acuerdo con @kan. El compilador de java lo hace, de hecho compila esto. Usé 1.6.0_27. Eclipse da el error exacto que le diste, ¿entonces tal vez lo está usando? –

Respuesta

2

He comprobado el código:

public class Test 
{ 
    public interface A<X> { 
     X get(); 
     void doStuff(X x); 
    } 
    public <T extends A<?>> void foo(T t) { 
     bar(t); 
    } 

    private <X> void bar(A<X> t) { 
     X x = t.get(); 
     t.doStuff(x); 
    } 
} 

funciona. javac 1.6.0_22. ¿Dónde tienes el error? ¿O estoy usando otro código?

+0

Gracias, lo veré el lunes en mi máquina en el trabajo, no sé exactamente qué versión de Java estoy utilizando allí. Acabo de probarlo en casa y no se compila utilizando javac 1.6.0_11 ... – misberner

+0

Por cierto, el error es simplemente " bar (Test.A ) en la prueba no se puede aplicar a (T)", con el marcador apuntando a la llamada de barra(). – misberner

1

El código:

public class Test 
{ 
    public interface A<X> { 
     X get(); 
     void doStuff(X x); 
    } 
    public <T extends A<?>> void foo(T t) { 
     bar(t); 
    } 

    private <X> void bar(A<X> t) { 
     X x = t.get(); 
     t.doStuff(x); 
    } 
} 

compila sólo para determinadas versiones de Java 1.6. Este bug fue registrado para el eclipse, pero fue rechazado con la siguiente explicación por Srikanth Sankaran:

creo que el comportamiento del eclipse compilador es correcto y se corresponde con JDK5 y JDK7 (más reciente). Parece que el comportamiento de JDK6 es una regresión que se ha solucionado desde entonces.

Básicamente, aquí hay una breve explicación de lo que está pasando aquí:

Dada la barra método genérico y el sitio de llamada como se indica por la barra (t), el algoritmo de inferencia no tiene limitaciones para trabajar con a inferir el tipo de la variable de tipo X. Por lo tanto, después de considerar los argumentos y tipo esperado de devolución, etc., X aún no se ha resuelto y según la especificación se resuelve como el límite inferior publicado - i.e X se infiere que es Objeto y el método se convierte en barra vacía (A) t); Como los parámetros reales no se pueden convertir a parámetros formales, el método inferido debe rechazarse, dejándonos sin candidatos aplicables. Por lo tanto, la llamada debe ser rechazada.

El motivo de la barra de llamadas ((A) t); Lo que sucede es que en este caso X se deduce que es "captura # 1-de?" y el método genérico parametrizado con esta sustitución se convierte en la barra vacía (A) para la cual se cumple la compatibilidad del parámetro.