tipificacion - ¿Por qué Java exige la compatibilidad del tipo de devolución para los métodos estáticos anulados?
tipificacion abo (4)
Bueno, la JVM probablemente podría hacerse para permitir eso, pero hablemos de por qué es una idea bastante mala desde la perspectiva del compilador.
Los datos de la instancia (incluido el tipo de la instancia) no es algo que sea un problema simple de resolver en tiempo de compilación. Obviamente es bien conocido en tiempo de ejecución. Si tengo una barra variable de tipo Bar, y llamo a s = bar.frob (), el compilador necesitaría realizar una ingeniería inversa de qué tipo es la barra para ver si el valor de retorno es aceptable. Si la determinación del tipo en el momento de la compilación es un problema súper difícil, esto hace que el compilador sea ineficiente en el mejor de los casos. En el peor de los casos, la respuesta es incorrecta y se obtienen errores de tiempo de ejecución que deberían haberse capturado en tiempo de compilación.
Según esta respuesta y esta respuesta , los métodos estáticos de Java no son virtuales y no pueden anularse. Intuitivamente, por lo tanto, esto debería funcionar (incluso si en el 99% de los casos es una programación peligrosa):
class Foo
{
public static String frob() {
return "Foo";
}
}
class Bar extends Foo
{
public static Number frob() {
return 123;
}
}
Sin embargo, en la práctica esto te lleva a:
Foo.java:10: frob() in Bar cannot override frob() in Foo; attempting to use incompatible return type
found : java.lang.Number
required: java.lang.String
public static Number frob() {
^
Ingenuamente, parece que Foo.frob()
y Bar.frob()
deberían tener nada que ver el uno con el otro; sin embargo, Java insiste en que lo hagan. ¿Por qué?
(NB: no quiero escuchar por qué sería una mala idea codificar de esta manera, quiero saber qué es lo que hace necesaria esta restricción en Java y / o el diseño de JVM).
Actualizado para agregar: para aquellos que piensan que el compilador se confundirá llamando a los métodos estáticos en las instancias, si permite esto: no lo hará. Ya tiene que resolver esto en el caso donde las firmas de métodos son compatibles:
class Foo
{
static String frob() {
return "Foo";
}
}
class Bar extends Foo
{
static String frob() {
return "Bar";
}
}
class Qux {
public static void main(String[] args) {
Foo f = new Foo();
Foo b = new Bar();
Bar b2 = new Bar();
System.out.println(f.frob());
System.out.println(b.frob());
System.out.println(b2.frob());
}
}
te consigue:
Foo
Foo
Bar
La pregunta es, ¿cuál es la razón concreta por la que no podría tan fácilmente (en el caso de las firmas incompatibles) conseguirte:
Foo
Foo
123
Esto se debe a que en Java, se llama a un método particular basado en el tipo de tiempo de ejecución del objeto y no en el tipo de tiempo de compilación del mismo. Sin embargo, los métodos estáticos son métodos de clase y, por lo tanto, el acceso a ellos siempre se resuelve durante el tiempo de compilación utilizando la información del tipo de tiempo de compilación. Es decir, qué pasaría si pudieras compilar lo anterior y usar código como este
Foo bar = new Bar();
bar.frob();
JLS 8.4.2 Firma del método , brevemente:
Dos métodos tienen la misma firma si tienen el mismo nombre y tipos de argumentos.
No se dice nada sobre la estática. Los métodos estáticos se pueden llamar a través de una instancia (o una referencia nula): ¿cómo debe resolverse el método si se hace referencia a una subclase a través de una declaración de superclase?
Considera lo siguiente:
public class Foo {
static class A {
public static void doThing() {
System.out.println("the thing");
}
}
static class B extends A {
}
static class C extends B {
public static void doThing() {
System.out.println("other thing");
}
}
public static void main(String[] args) {
A.doThing();
B.doThing();
C.doThing();
}
}
¡Ejecutarlo! Compila e imprime
the thing
the thing
other thing
Los métodos estáticos heredan en cierto modo, en el sentido de que B.doThing
se traduce en una llamada a A.doThing
y se puede anular.
Parece que fue principalmente una decisión de juicio para el JLS. Sin embargo, la forma más específica en que el JLS parece abordar esto es la sección 8.2 , que simplemente no dice que los métodos estáticos no se hereden.