Os métodos estáticos são herdados em Java?


142

Eu estava lendo Um Guia do Programador para Certificação Java ™ SCJP de Khalid Mughal.

No capítulo Herança, explica que

A herança de membros está intimamente ligada à sua acessibilidade declarada. Se um membro da superclasse for acessível por seu nome simples na subclasse (sem o uso de nenhuma sintaxe extra como super), esse membro será considerado herdado

Ele também menciona que métodos estáticos não são herdados. Mas o código abaixo é perfeitamente correto:

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();
    }
}

Como posso usar diretamente display()nas aulas B? Ainda mais, B.display()também funciona.

A explicação do livro se aplica apenas a métodos de instância?


stackoverflow.com/questions/4716040/… tem informações interessantes.
24512 Mat

Não é isso que diz minha cópia, 1ª edição. Forneça uma cotação real.
Marquês de Lorne

Respostas:


178

Todos os métodos acessíveis são herdados pelas subclasses.

Dos tutoriais Java da Sun :

Uma subclasse herda todos os membros públicos e protegidos de seu pai, não importa em que pacote esteja a subclasse. Se a subclasse estiver no mesmo pacote que seu pai, ela também herdará os membros privados do pai. Você pode usar os membros herdados como estão, substituí-los, ocultá-los ou complementá-los com novos membros

A única diferença entre os métodos estáticos herdados (classe) e os métodos não estáticos herdados (instância) é que, quando você escreve um novo método estático com a mesma assinatura, o antigo método estático fica oculto, não é substituído.

Da página da diferença entre substituir e ocultar.

A distinção entre ocultar e substituir tem implicações importantes. A versão do método substituído que é chamada é a da subclasse. A versão do método oculto que é chamado depende se ele é chamado da superclasse ou da subclasse


tão herdado diz respeito à possibilidade de substituir esse membro na subclasse?
Algorithmist

Bem, isso faz parte da herança, mas não é tudo. Eu diria que as outras partes principais da herança são a reutilização de código e o polimorfismo.
yincrash

A redefinição também possui algumas regras, como a substituição?
Surender Thakran /

2
@ Algorithmist não, não exatamente. Todas as coisas que sua subclasse vê mais adiante na hierarquia são coisas que sua classe herdou. Mas os métodos estáticos herdados não podem ser substituídos, apenas ocultos ("declarados novamente" com a mesma assinatura). Portanto, você também pode declarar seus métodos estáticos como finais, não importa. Qual método estático que será chamado é conhecido em tempo de compilação. Com métodos de instância não final, a resolução deve ser adiada para o tempo de execução, pois pode ser substituída.
Martin Andersson

1
Seu último parágrafo está completamente comprometido !!! "A versão do método substituído que é chamada é a da subclasse" isso não é verdade: Digamos: A versão do método substituído que é chamada é determinada apenas em tempo de execução pela JVM relacionada a qual objeto fez o chamar :)
mounaim

14

Se é isso que o livro realmente diz, está errado. [1]

A especificação da linguagem Java # 8.4.8 declara:

8.4.8 Herança, substituição e ocultação

Uma classe C herda de sua superclasse direta todos os métodos concretos m (estáticos e de instância) da superclasse para os quais todos os seguintes itens são verdadeiros:

  • m é um membro da superclasse direta de C.

  • m é público, protegido ou declarado com acesso ao pacote no mesmo pacote que C.

  • Nenhum método declarado em C possui uma assinatura que é uma sub-assinatura (§8.4.2) da assinatura de m.

[1] Não diz isso na minha cópia, 1ª edição, 2000.


13

Você pode experimentar a diferença no código a seguir, que é uma pequena modificação em seu 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();
    }
}

Isso ocorre porque métodos estáticos são métodos de classe.

A.display () e B.display () chamarão o método de suas respectivas classes.


1
Invocar um método estático em uma instância como a que você está tentando não funcionará em java.
Lucas C. Feijo 24/08

É o que este programa explica, instanciar o objeto B e esperar que a herança funcione não será possível com membros estáticos. Tente tomar mesmo código no seu eclipse / qualquer IDE ou compilar usando javac e executá-lo
Gaurav

2
@ LucasC.Feijo na verdade eu funciona. Pelo menos no meu IDE (eclipse). Acabei de receber um aviso. Talvez não seja um bom estilo ... mas essa é uma história diferente.
Dingalapadum

2
@ LucasC.Feijo chamar um método estático em uma instância não é recomendado. Mas funciona da mesma maneira que chamar um método estático no nome de uma classe.
Ziyang Zhang

5

B.display () funciona porque a declaração estática faz com que o método / membro pertença à classe, e não qualquer instância de classe específica (também conhecida como Object). Você pode ler mais sobre isso aqui .

Outro aspecto a ser observado é que você não pode substituir um método estático, sua subclasse pode declarar um método estático com a mesma assinatura, mas seu comportamento pode ser diferente do que você esperaria. Esta é provavelmente a razão pela qual não é considerada herdada. Você pode conferir o cenário problemático e a explicação aqui .


3

Os métodos estáticos em Java são herdados, mas não podem ser substituídos. Se você declarar o mesmo método em uma subclasse, oculte o método da superclasse em vez de substituí-lo. Métodos estáticos não são polimórficos. No momento da compilação, o método estático será vinculado estaticamente.

Exemplo:

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();
    }
}

Você obterá o seguinte:

Writing
Writing
Writing
Writing book

2

Os métodos estáticos são herdados em Java, mas não participam do polimorfismo. Se tentarmos substituir os métodos estáticos, eles apenas ocultarão os métodos estáticos da superclasse em vez de substituí-los.


Não vejo uma razão para negar voto a esta resposta. É nítido e claro, pelo menos a primeira parte. A segunda parte não deve ser tomada muito tecnicamente, caso contrário, tudo bem. Para esclarecer, nos métodos de substituição, o tipo de retorno pode mudar (para subtipo), enquanto que esse não é o caso dos métodos estáticos. Tecnicamente, 'tentativa de substituir' não se aplica a métodos estáticos, então tudo o que podemos dizer é que não podemos.
sharhp

2

Esse conceito não é tão fácil quanto parece. Podemos acessar membros estáticos sem herança, que é a relação HasA. Podemos acessar membros estáticos estendendo a classe pai também. Isso não implica que seja uma relação ISA (herança). Na verdade, os membros estáticos pertencem à classe e o static não é um modificador de acesso. Enquanto os modificadores de acesso permitirem acessar os membros estáticos, podemos usá-los em outras classes. Por exemplo, se for público, estará acessível dentro do mesmo pacote e também fora do pacote. Para particulares, não podemos usá-lo em nenhum lugar. Por padrão, podemos usá-lo apenas dentro do pacote. Mas, para os protegidos, temos que estender a super classe. Portanto, obter o método estático para outra classe não depende de ser estático. Depende dos modificadores de acesso. Então, na minha opinião, Membros estáticos podem acessar se os modificadores de acesso permitirem. Caso contrário, podemos usá-los como usamos na relação Hasa. E tem uma relação não é herança. Novamente, não podemos substituir o método estático. Se podemos usar outro método, mas não podemos substituí-lo, é a relação HasA. Se não pudermos substituí-los, não será uma herança. Portanto, o escritor estava 100% correto.


Estender a classe pai é um relacionamento 'is-a'. Se o acesso for privado, você poderá usá-lo de dentro da classe. 'protected' inclui classes derivadas e classes no pacote atual. Muitos erros aqui.
Marquês de Lorne #

0

O método estático é herdado na subclasse, mas não é polimorfismo. Quando você escreve a implementação do método estático, o método de classe do pai fica oculto, não substituído. Pense, se não for herdado, como você poderá acessar sem classname.staticMethodname();?


0

Todos os membros públicos e protegidos podem ser herdados de qualquer classe, enquanto os membros padrão ou do pacote também podem ser herdados da classe dentro do mesmo pacote que o da superclasse. Não depende se é membro estático ou não estático.

Mas também é verdade que a função de membro estático não participa da ligação dinâmica. Se a assinatura desse método estático for a mesma na classe pai e filho, o conceito de Shadowing se aplica, não o polimorfismo.


0

Você pode substituir métodos estáticos, mas se você tentar usar o polimorfismo, eles funcionarão de acordo com o escopo da classe (ao contrário do 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();


    }


}

No primeiro caso, o / p é o "no método estático de B" # substituição bem-sucedida No segundo caso, o / p é "no método estático de A" # método estático - não considerará polimorfismo


-1

Podemos declarar métodos estáticos com a mesma assinatura na subclasse, mas isso não é considerado de substituição, pois não haverá polimorfismo em tempo de execução. time (substituindo no tempo de execução) Portanto, a resposta é 'Não'.


2
Não sei por que as pessoas sempre votam negativamente e não dão o motivo da votação negativa.
precisa saber é o seguinte

Esta resposta é sobre substituição. A questão é sobre herança.
Marquês de Lorne #

-1

Muitos expressaram sua resposta em palavras. Esta é uma explicação extensa nos 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

Portanto, esta é a conclusão:

  1. Quando chamamos a estática de maneira estática via., Ela procurará a estática definida nessa classe ou a classe mais próxima da cadeia de herança. Isso prova que métodos estáticos são herdados.
  2. Quando o método estático é chamado de uma instância, ele chama o método estático definido no tipo de tempo de compilação.
  3. O método estático pode ser chamado de uma nullinstância. Meu palpite é que o compilador usará o tipo de variável para encontrar a classe durante a compilação e a converterá na chamada de método estático apropriada.

1
O mero código não é uma explicação, é uma demonstração. Uma resposta a esta pergunta deve citar referências normativas, não apenas exibir o comportamento de alguma implementação não declarada.
Marquês de Lorne

-2

Membros estáticos são membros universais. Eles podem ser acessados ​​de qualquer lugar.


4
pode ser acessado de qualquer lugar , literalmente, errado: estático! = escopo. você pode querer esclarecer :-)
kleopatra

Na verdade, essa resposta é boa quando considerada literalmente. Não consigo pensar em um único lugar no código onde o código possa ir e que não seja possível acessar um membro estático da classe. Você pode acessá-los em inicializadores estáticos, construtores estáticos, construtores de instância, métodos, propriedades, em diferentes classes, em qualquer escopo. Desde que a classe e o método estático sejam públicos, eles podem ser acessados ​​de qualquer lugar, assumindo que não haja dependências circulares nos inicializadores estáticos. Em essência, os membros estáticos não são herdados, são apenas métodos em nível de classe (ou seja, universais) acessíveis a partir de qualquer lugar.
Triynko 24/02

@Triynko A resposta está errada no caso de métodos privados ou protegidos por pacotes acessados ​​de fora do pacote.
Marquês de Lorne #

@kleopatra - fora de tópico. Java Swing? as pessoas realmente usam isso hoje em dia?
MasterJoe2

O @Pavan tenta chamar estática privada de fora da classe. Isso não vai funcionar.
Rakesh Yadav

-2

Os membros estáticos não serão herdados da subclasse porque a herança é apenas para membros não estáticos. E os membros estáticos serão carregados dentro do conjunto estático pelo carregador de classes. A herança é apenas para os membros carregados dentro do objeto


Completamente incorreto. Veja JLS # 8.4.8 .
Marquês de Lorne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.