Curioso error de tipo en genéricos de Java

He encontrado un problema extraño con el siguiente código (bueno, no exactamente este código):

public class CompilationProblems1 {

  static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);
  static Box<? extends Class<? extends AlcoholicBewerage>> boxOfOneBeer = boxOf(Beer.class);
  static Box<Class<? extends AlcoholicBewerage>> boxOfBeerAndVodka = boxOf(Beer.class, Vodka.class);

  interface AlcoholicBewerage {}

  class Beer implements AlcoholicBewerage {}

  class Vodka implements AlcoholicBewerage {}

  static class Box<T> {}

  static <E> Box<E> boxOf(E e) {
      return new Box<E>();
  }

  static <E> Box<E> boxOf(E e1, E e2) {
      return new Box<E>();
  }
}

La primera declaración brokenBoxOfOneBeerda un error de compilación:

found   : lt.tool.CompilationProblems1.Box<java.lang.Class<lt.tool.CompilationProblems1.Beer>>
required: lt.tool.CompilationProblems1.Box<java.lang.Class<? extends   lt.tool.CompilationProblems1.AlcoholicBewerage>>
static Box<Class<? extends AlcoholicBewerage>> brokenBoxOfOneBeer = boxOf(Beer.class);

Este error ocurre en OpenJDK 6, Eclipse e IntelliJ. Entiendo que es una limitación del inferenciador de tipos.

En el tercer caso ( boxOfBeerAndVodka), el compilador puede inferir el tipo covariante correcto porque tiene dos subtipos para elegir, creo. Pero, ¿por qué el compilador no puede compilar la primera declaración, pero está de acuerdo con la segunda?

Respuesta 1

Pero, ¿por qué el compilador no puede compilar la primera declaración, pero está de acuerdo con la segunda?

En ambos casos, la expresión boxOf(Beer.class)tiene tipo Box<Class<Beer>>.

  • La primera declaración necesita que tenga tipo Box<Class<? extends AlcoholicBewerage>>; ya Box<Class<Beer>>que no es un subtipo de Box<Class<? extends AlcoholicBewerage>>, esto no funciona. ( Class<Beer>es un subtipo de Class<? extends AlcoholicBewerage>, pero debido a la invariancia, esto no implica que Box<Class<Beer>>sea ​​un subtipo de Box<Class<? extends AlcoholicBewerage>>).
  • La segunda declaración necesita que tenga tipo Box<? extends Class<? extends AlcoholicBewerage>>, lo que hace. Class<Beer>es un subtipo de Class<? extends AlcoholicBewerage>, ergo Box<Class<Beer>>es un subtipo de Box<? extends Class<? extends AlcoholicBewerage>>.

Es decir, exactamente lo mismo está sucediendo en sus declaraciones como sucedería en:

List<Object> foo = new ArrayList<String>(); // doesn't work
List<? extends Object> bar = new ArrayList<String>(); // works

Simplemente parece más complicado porque en lugar de Objecty Stringtiene otro nivel de tipos genéricos.

Respuesta: 2

Estoy creando una aplicación de Android en Java, uso una variable Enum en un escenario .setText para un TextView XML, entiendo completamente que mi Enum está en el tipo de datos incorrecto, pero necesito su ayuda para encontrar una alternativa ...

Estoy tratando de escribir un código para firmar y validar las cargas útiles utilizando mis claves privadas / públicas en Java siguiendo los estándares de JOSE. Necesito usar el algoritmo de cifrado PS256 para esto. Estoy usando connect2id '...

Estoy tratando de crear un analizador para el código fuente como este: [tabla de códigos 1.0] tabla de códigos code_table_name id = 500 desc = "mi tabla de códigos una" tabla de códigos finales ... y aquí debajo está la gramática I ...

Digamos que tengo un método que toma un parámetro y devuelve un Mono <Integer> que se completa de forma asíncrona. Por ejemplo: Aleatorio aleatorio = nuevo Aleatorio (); ScheduledExecutorService ...