¿Los métodos estáticos se heredan en Java?

142

Estaba leyendo la Guía del programador para la certificación SCJP Java ™ de Khalid Mughal.

En el capítulo Herencia, explica que

La herencia de los miembros está estrechamente vinculada a su accesibilidad declarada. Si un miembro de la superclase es accesible por su nombre simple en la subclase (sin el uso de ninguna sintaxis adicional como super), ese miembro se considera heredado

También menciona que los métodos estáticos no se heredan. Pero el siguiente código está perfectamente bien:

class A
{
    public static void display()
    {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A
{
    public void show()
    {
        // This works - accessing display() by its simple name -
        // meaning it is inherited according to the book.
        display();
    }
}

¿Cómo puedo usar directamente display()en clase B? Aún más, B.display()también funciona.

¿La explicación del libro solo se aplica a los métodos de instancia?

Algoritmo
fuente
stackoverflow.com/questions/4716040/… tiene información interesante.
Mat
Eso no es lo que dice en mi copia, primera edición. Proporcione una cotización real.
Marqués de Lorne

Respuestas:

179

Todos los métodos accesibles son heredados por subclases.

De los tutoriales de Sun Java :

Una subclase hereda todos los miembros públicos y protegidos de su padre, sin importar en qué paquete esté la subclase. Si la subclase está en el mismo paquete que su padre, también hereda los miembros privados del paquete del padre. Puede usar los miembros heredados tal cual, reemplazarlos, ocultarlos o complementarlos con nuevos miembros

La única diferencia con los métodos estáticos heredados (clase) y los métodos heredados no estáticos (instancia) es que cuando escribe un nuevo método estático con la misma firma, el método estático antiguo simplemente se oculta, no se anula.

De la página en la diferencia entre anular y ocultar.

La distinción entre ocultar y anular tiene implicaciones importantes. La versión del método anulado que se invoca es la de la subclase. La versión del método oculto que se invoca depende de si se invoca desde la superclase o la subclase

yincrash
fuente
¿heredado se relaciona con si podemos anular ese miembro en la subclase?
Algorithmist
Bueno, eso es parte de la herencia, pero no todo. Diría que las otras partes importantes de la herencia son la reutilización de códigos y el polimorfismo.
yincrash
¿La redefinición también tiene algunas reglas como la de anulación?
Surender Thakran
2
@Algorithmist no, no exactamente. Todas las cosas que su subclase ve más arriba en la jerarquía, son cosas que su clase heredó. Pero los métodos estáticos que se heredan, no pueden anularse, solo ocultarse ("redeclararse" con la misma firma). Por lo tanto, también puede declarar sus métodos estáticos como finales, no importa. El método estático que se invocará se conoce en tiempo de compilación. Con los métodos de instancia no final, la resolución debe diferirse al tiempo de ejecución, ya que pueden anularse.
Martin Andersson
1
¡Tu último párrafo está completamente socavado! "La versión del método de anulación que se invoca es la de la subclase" esto no es cierto: Digamos: la versión del método de anulación que se invoca solo se determina en el tiempo de ejecución por la JVM relacionada con qué objeto ha realizado el llamar :)
mounaim
14

Si eso es lo que realmente dice el libro, está mal. [1]

La especificación del lenguaje Java # 8.4.8 establece:

8.4.8 Herencia, anulación y ocultación

Una clase C hereda de su superclase directa todos los métodos concretos m (tanto estáticos como de instancia) de la superclase para los cuales se cumple todo lo siguiente:

  • m es miembro de la superclase directa de C.

  • m es público, protegido o declarado con acceso a paquetes en el mismo paquete que C.

  • Ningún método declarado en C tiene una firma que sea una sub firma (§8.4.2) de la firma de m.

[1] No dice eso en mi copia, primera edición, 2000.

Marqués de Lorne
fuente
13

Puede experimentar la diferencia en el siguiente código, que es una ligera modificación sobre su código.

class A {
    public static void display() {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A {
    public void show() {
        display();
    }

    public static void display() {
        System.out.println("Inside static method of this class");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        // prints: Inside static method of this class
        b.display();

        A a = new B();
        // prints: Inside static method of superclass
        a.display();
    }
}

Esto se debe a que los métodos estáticos son métodos de clase.

A.display () y B.display () llamarán al método de sus respectivas clases.

Gaurav
fuente
1
Invocar un método estático en una instancia como la que está intentando no funcionará en Java.
Lucas C. Feijo
Eso es lo que explica este programa, crear instancias de objetos de B y esperar que la herencia funcione no será posible con miembros estáticos. Intente tomar el mismo código en su eclipse / any ide o compile usando javac y ejecútelo
Gaurav
2
@ LucasC.Feijo en realidad sí funciona. Al menos en mi IDE (eclipse). Acabo de recibir una advertencia. Sin embargo, puede que no sea un buen estilo ... pero esa es una historia diferente.
dingalapadum
2
@ LucasC.Feijo llamar a un método estático en una instancia no se recomienda. Pero funciona igual que llamar a un método estático en un nombre de clase.
Ziyang Zhang
5

B.display () funciona porque la declaración estática hace que el método / miembro pertenezca a la clase, y no a ninguna instancia de clase en particular (también conocida como Object). Puedes leer más sobre esto aquí .

Otra cosa a tener en cuenta es que no puede anular un método estático, puede hacer que su subclase declare un método estático con la misma firma, pero su comportamiento puede ser diferente de lo que esperaría. Esta es probablemente la razón por la que no se considera heredada. Puede consultar el escenario problemático y la explicación aquí .

Kai
fuente
3

Los métodos estáticos en Java se heredan, pero no se pueden anular. Si declara el mismo método en una subclase, oculta el método de la superclase en lugar de anularlo. Los métodos estáticos no son polimórficos. En el momento de la compilación, el método estático estará vinculado estáticamente.

Ejemplo:

public class Writer {
    public static void write() {
        System.out.println("Writing");
    }
}

public class Author extends Writer {
    public static void write() {
        System.out.println("Writing book");
    }
}

public class Programmer extends Writer {

    public static void write() {
        System.out.println("Writing code");
    }

    public static void main(String[] args) {
        Writer w = new Programmer();
        w.write();

        Writer secondWriter = new Author();
        secondWriter.write();

        Writer thirdWriter = null;
        thirdWriter.write();

        Author firstAuthor = new Author();
        firstAuthor.write();
    }
}

Obtendrás lo siguiente:

Writing
Writing
Writing
Writing book

fuente
2

Los métodos estáticos se heredan en Java pero no participan en el polimorfismo. Si intentamos anular los métodos estáticos, simplemente ocultarán los métodos estáticos de la superclase en lugar de anularlos.

Praveen Kumar
fuente
No veo una razón para rechazar esta respuesta. Es crujiente y claro, al menos la primera parte. La segunda parte no debe tomarse demasiado técnicamente, de lo contrario está bien. Para aclarar, en los métodos de anulación, el tipo de retorno puede cambiar (a subtipo), mientras que este no es el caso con los métodos estáticos. Técnicamente, el 'intento de anulación' no se aplica a los métodos estáticos, por lo que todo lo que podemos decir es que no podemos.
sharhp
2

Este concepto no es tan fácil como parece. Podemos acceder a miembros estáticos sin herencia, que es la relación HasA. Podemos acceder a miembros estáticos extendiendo también la clase padre. Eso no implica que sea una relación ISA (Herencia). En realidad, los miembros estáticos pertenecen a la clase, y static no es un modificador de acceso. Mientras los modificadores de acceso permitan acceder a los miembros estáticos, podemos usarlos en otras clases. Al igual que si es público, será accesible dentro del mismo paquete y también fuera del paquete. Para privado no podemos usarlo en ningún lado. Por defecto, podemos usarlo solo dentro del paquete. Pero para protegidos tenemos que extender la superclase. Por lo tanto, llevar el método estático a otra clase no depende de ser estático. Depende de los modificadores de acceso. Entonces, en mi opinión, Los miembros estáticos pueden acceder si los modificadores de acceso lo permiten. De lo contrario, podemos usarlos como usamos por relación Hasa. Y tiene una relación que no es herencia. Nuevamente, no podemos anular el método estático. Si podemos usar otro método pero no podemos anularlo, entonces es la relación HasA. Si no podemos anularlos, no será herencia, por lo que el escritor estaba 100% correcto.

Noman_ibrahim
fuente
Extender la clase padre es una relación 'es-a'. Si el acceso es privado, puede usarlo desde la clase. 'protegido' incluye clases derivadas y clases en el paquete actual. Demasiados errores aquí.
Marqués de Lorne
0

El método estático se hereda en la subclase, pero no es polimorfismo. Cuando escribe la implementación del método estático, el método de clase del padre se sobre oculta, no se anula. Piense, si no se hereda, ¿cómo puede acceder sin él classname.staticMethodname();?

usuario4016405
fuente
0

Todos los miembros públicos y protegidos se pueden heredar de cualquier clase, mientras que los miembros predeterminados o del paquete también se pueden heredar de la clase dentro del mismo paquete que el de la superclase. No depende de si es miembro estático o no estático.

Pero también es cierto que la función miembro estática no participa en el enlace dinámico. Si la firma de ese método estático es la misma tanto en la clase principal como en la secundaria, se aplica el concepto de Sombreado, no el polimorfismo.

shubham
fuente
0

Puede anular los métodos estáticos, pero si intenta usar el polimorfismo, entonces funcionan de acuerdo con el alcance de la clase (Contrariamente a lo que normalmente esperamos).

public class A {

    public static void display(){
        System.out.println("in static method of A");
    }
}

public class B extends A {

    void show(){
        display();
    }

     public static void display(){
        System.out.println("in static method of B");
    }

}
public class Test {

    public static void main(String[] args){
        B obj =new B();
        obj.show();

        A a_obj=new B();
        a_obj.display();


    }


}

En el primer caso, o / p es el "en el método estático de B" # anulación exitosa

Manav Garekar
fuente
-1

Podemos declarar métodos estáticos con la misma firma en la subclase, pero no se considera una anulación, ya que no habrá ningún polimorfismo en tiempo de ejecución. Debido a que todos los miembros estáticos de una clase se cargan en el momento de la carga de la clase, por lo que decide compilar tiempo (anulación en tiempo de ejecución) Por lo tanto, la respuesta es 'No'.

NGK
fuente
2
No sé por qué las personas siempre votan negativamente y no dan la razón de la votación negativa.
surajs1n
Esta respuesta es sobre anular. La pregunta es sobre la herencia.
Marqués de Lorne
-1

Muchos han expresado su respuesta en palabras. Esta es una explicación extendida en los códigos:

public class A {
    public static void test() {
        System.out.println("A");
    }
    public static void test2() {
        System.out.println("Test");
    }
}

public class B extends A {
    public static void test() {
        System.out.println("B");
    }
}

// Called statically
A.test();
B.test();
System.out.println();

// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();

// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();

// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();

// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();

// Testing whether null instance works
A nullObj = null;
nullObj.hi();

Resultados:

A
B

Test
Test

A
B

Test
Test

A

A

Por lo tanto, esta es la conclusión:

  1. Cuando llamamos a la estática de manera estática vía., Buscará la estática definida en esa clase, o la clase más cercana a la de la cadena de herencia. Esto prueba que los métodos estáticos se heredan.
  2. Cuando se llama al método estático desde una instancia, llama al método estático definido en el tipo de tiempo de compilación.
  3. Se puede llamar al método estático desde una nullinstancia. Mi conjetura es que el compilador usará el tipo de variable para encontrar la clase durante la compilación y traducir eso a la llamada al método estático apropiado.
Jai
fuente
1
El mero código no es una explicación, es una demostración. Una respuesta a esta pregunta debería citar referencias normativas, no solo exhibir el comportamiento de alguna implementación no declarada.
Marqués de Lorne
-2

Los miembros estáticos son miembros universales. Se puede acceder desde cualquier lugar.

Pavana
fuente
44
se puede acceder desde cualquier lugar tomado literalmente, eso está mal: static! = scope. es posible que desee aclarar :-)
kleopatra
En realidad, esta respuesta está bien cuando se toma literalmente. No puedo pensar en un solo lugar en el código donde pueda ir el código que no pueda acceder a un miembro estático de la clase. Puede acceder a ellos en inicializadores estáticos, constructores estáticos, constructores de instancias, métodos, propiedades, en diferentes clases, en cualquier ámbito. Mientras la clase y el método estático sean públicos, se puede acceder a ellos desde cualquier lugar, suponiendo que no haya dependencias circulares en los inicializadores estáticos. En esencia, los miembros estáticos no se heredan, son solo métodos de nivel de clase (es decir, universales) a los que se puede acceder desde cualquier lugar.
Triynko
@Triynko La respuesta es incorrecta en el caso de métodos que son privados o protegidos por paquetes a los que se accede desde fuera del paquete.
Marqués de Lorne
@kleopatra - fuera del tema. java swing? ¿La gente realmente usa eso en estos días?
MasterJoe2
@Pavan intenta llamar a la estática privada desde fuera de la clase. No va a funcionar
Rakesh Yadav
-2

Los miembros estáticos no se heredarán a la subclase porque la herencia es solo para miembros no estáticos. Y los cargadores de clases cargarán los miembros estáticos dentro del grupo estático. La herencia es solo para aquellos miembros que están cargados dentro del objeto

Ashwini E
fuente
Completamente incorrecto Ver JLS # 8.4.8 .
Marqués de Lorne