valores tipos salir retornar retornan reservada que palabra metodos metodo invoca como comando java generics override method-overriding

tipos - salir de un metodo void java



La anulación de un método con un tipo de retorno genérico falla después de agregar un parámetro (2)

De acuerdo con la salida del compilador, las firmas del método son diferentes en ambos ejemplos (compile el código con la opción -Xlint:unchecked para confirmarlo):

<X>getSupplier() in A (m2) 1st snippet getSupplier() in B (m1) <X>getSuppliers(Collection<String> strings) in A (m2) 2nd snippet getSuppliers(Collection<String> strings) in B (m1)

De acuerdo con la especificación JLS , la firma de un método m 1 es una subscripción de la firma de un método m 2 si:

  • m 2 tiene la misma firma que m 1 , o

  • la firma de m 1 es igual a la eliminación de la firma de m 2 .

La primera declaración está fuera del juego: las firmas de los métodos son diferentes. Pero ¿qué pasa con la segunda afirmación y borrado?

Anulación válida

B.getSupplier() (m 1 ) es una subscripción de A.<X>getSupplier() (m 2 ), porque:

  • la firma de m 1 es igual a la eliminación de la firma de m 2

<X>getSupplier() después del borrado es igual a getSupplier() .

Anulación no válida

B.getSuppliers(...) (m 1 ) no es una subscripción de A.<X>getSuppliers(...) (m 2 ), porque:

  • la firma de m 1 no es lo mismo que el borrado de la firma de m 2

La firma de m 1 :

getSuppliers(Collection<String> strings);

Borrado de la firma de m 2 :

getSuppliers(Collection strings);

Cambiar el argumento m 1 de la Collection<String> a la Collection sin Collection elimina un error, en este caso m 1 se convierte en una subsignatura de m 2 .

Conclusión

Primer fragmento de código (anulación válida) : las firmas del método en las clases padre e hijo son diferentes inicialmente. Pero, después de aplicar el borrado al método principal, las firmas se vuelven iguales.

Fragmento del segundo código (anulación no válida) : las firmas del método son diferentes inicialmente y siguen siendo diferentes después de aplicar el borrado al método principal.

Me pregunto por qué este es un reemplazo válido:

public abstract class A { public abstract <X> Supplier<X> getSupplier(); public static class B extends A { @Override public Supplier<String> getSupplier() { return String::new; } } }

Considerando que esto no es:

public abstract class A { public abstract <X> Supplier<X> getSuppliers(Collection<String> strings); public static class B extends A { @Override public Supplier<String> getSuppliers(Collection<String> strings) { return String::new; } } }

Según JLS §8.4.8.1 , B.getSupplier debe ser un A.getSupplier :

Un método de instancia mC declarado o heredado por la clase C, anula desde C otro método mA declarado en la clase A, si todos los siguientes son verdaderos:

  • ...
  • La firma de mC es una subscripción (§8.4.2) de la firma de mA.
  • ...

Las suscripciones se definen en JLS §8.4.2 :

Dos métodos o constructores, M y N, tienen la misma firma si tienen el mismo nombre, los mismos parámetros de tipo (si los hay) (§8.4.4) y, después de adaptar los tipos de parámetros formales de N a los parámetros de tipo de M, los mismos tipos de parámetros formales.

La firma de un método m1 es una subscripción de la firma de un método m2 si:

  • m2 tiene la misma firma que m1, o
  • La firma de m1 es la misma que el borrado (§4.6) de la firma de m2.

Así que parece que B.getSupplier es una A.getSupplier de A.getSupplier pero B.getSuppliers no es una A.getSuppliers de A.getSuppliers .

Me pregunto cómo puede ser el caso.

Si B.getSupplier es una subsignatura de A.getSupplier porque tiene el mismo borrado, entonces B.getSuppliers también debe tener el mismo borrado que A.getSuppliers . Esto debería ser suficiente para que los getSuppliers sean legales, pero no lo es.

Si B.getSupplier es una subsignatura de A.getSupplier porque tiene la misma firma, entonces me pregunto qué significa exactamente "los mismos parámetros de tipo (si los hay)".

Si se consideran los parámetros de tipo, entonces deben tener diferentes parámetros de tipo: A.getSupplier tiene el parámetro de tipo X , B.getSupplier no tiene ninguno.
Si los parámetros de tipo no son considerados, ¿cómo es diferente getSuppliers ?

Esto es más bien una pregunta académica sobre las anulaciones y los genéricos, así que no sugiera un código de refactorización (como mover el parámetro de tipo X a la clase, etc.).

Estoy buscando una respuesta formal, basada en JLS.

Desde mi punto de vista, B.getSupplier no debería poder anular A.getSupplier ya que no tienen los mismos parámetros de tipo. Esto hace que el siguiente código (que produce la ClassCastException ) sea legal:

A b = new B(); URL url = b.<URL>getSupplier().get();


En el momento en que agregó el parámetro, dejó de ser una anulación y se convirtió en una sobrecarga.

Los genéricos no tienen nada que ver con eso.