Métodos Static

Pessoal, estava lendo um livro da Deitel, e no mesmo diz que um método static, herdado para uma subclasse, não poder ser sobrescrito por essa subclasse. Testei esta informação várias vezes, e a subclasse sobrescreve um método static sim, o que o livro quis dizer?

Se na me engano na realidade vc redefine, jamais sobrescreve.

1 curtida

[quote=kakabill]Pessoal, estava lendo um livro da Deitel, e no mesmo diz que um método static, herdado para uma subclasse, não poder ser sobrescrito por essa subclasse. Testei esta informação várias vezes, e a subclasse sobrescreve um método static sim, o que o livro quis dizer?
[/quote]

Poste seu código para ficar mais fácil de explicar usando o seu exemplo.

bcartaxo - pensei nisso também, mas deve ter alguma maneira de provar isso através de algum codigo que eu estou criando um novo método, mas não sobrescrevendo. Por que fiz alguns testes e tenho certeza que a subclasse herda da superclasse um método static.

[quote=kakabill]Pessoal, estava lendo um livro da Deitel, e no mesmo diz que um método static, herdado para uma subclasse, não poder ser sobrescrito por essa subclasse. Testei esta informação várias vezes, e a subclasse sobrescreve um método static sim, o que o livro quis dizer?
[/quote]

Para que o método possa ser subrescrito ele tem que ser herdado em primeiro lugar. Metodos estáticos não são herdados, tal como os construtores não sao (pq de certa forma eles são estáticos tb)

Então vc pode escrever o mesmo método numa subclasse , mas isso é overloading (sobrecarga ) e não overrriding (sobrescrita)

Tem como provar sim kra. A diferença é q ao redefinir vc n pode fazer chamadas polimórficas. Se vc tiver uma instância de uma classe filha atribuída a uma variável do tipo pai, ao chamar o método estático q foi redefinido na filha vc n terá uma chamada polimórfica, que seria o natural se fossem métodos sobrestritos.

sergiotaborda - cara, métodos statics são herdados sim, faz um teste, faz uma subclasse herdar um método static e depois chama esse método usando uma variavel da subclasse referenciando um objeto da subclasse. Ele será herdado.

bcartaxo - verdade cara, muito interessante, o método chamado foi o da classe pai, mesmo o objeto referenciado sendo da classe filha. Dei uma pesquisada, é porque metodos static são resolvidos em tempo de compilação não de execução - vinculação estática, ja ouviu falar??

For Favor kakabill reveja toda a parte de OO novamente e quem sabe a parte de Static fica mais clara para você.

[EDIT]
http://www.guj.com.br/posts/list/64337.java
[/EDIT]

Classe A com o método fazerAlgo():

public class A {
    public static void fazerAlgo() {
    }
}

Classe B que estende A:

public class B extends A {
    public static void fazerAlgo(String a) {
    }

    public static void fazerAlgo() {
    }

    public void fazerAlgo(Integer b) {
    }
}

Em outras palavras: em B, você pode sobrecarregar (overload) o método fazerAlgo() mantendo a mesma assinatura do método de A (inclusive o static), ou alterando o número de parâmetros do método sem precisar manter o static.

Se você tentar colocar um método em B com a mesma assinatura do método de A, retirando o static, o compilador não permitirá isso, alegando que você não pode sobreescrever (override) o método fazerAlgo().

[quote=kakabill]sergiotaborda - cara, métodos statics são herdados sim, faz um teste, faz uma subclasse herdar um método static e depois chama esse método usando uma variavel da subclasse referenciando um objeto da subclasse. Ele será herdado.
[/quote]

A noção de herança implica a noção de objeto. Um método estático pertence à classe mas não ao objeto e portanto não pode ser herdado!

Quando a classe filha escreve um método com a mesma assinatura que a classe pai, o que está acontecendo é shadowing (sombreamento) e não herança. Shadowing permite que vc use os mesmos nomes (polimorfismo estático) mas a funcionalidade não é herdada.

É por isto que um método estático não pode ser abstract e ser final é redundante.


class Pai {
  
   public static char m(){
       return 'p';
   }

}

class Filho extends Pai{
  
   public static char m(){
       return 'f';
   }

}

Vc está fazendo isto:


Pai p = new Filho();

p.m();

É possível fazer isto porque Java permite que métodos estáticos sejam invocados a partir dos objetos, mas o que o Java está fazendo é invocar m() na classe Pai. (e não na Filho, como seria de esperar se houvesse herança).
Fazer este tipo de invocação , embora possível, é errado. Métodos estáticos devem ser chamados diretamente na classe (Pai.m()) exatamente para ser claro o que estamos fazendo.

Por favor, reavalie os seus conceitos de Herança, Polimorfismo, Shadowing e Classe.

Vc deve ta utilizando sobrecarga, estude sobre isso

FAlow

public class ClassePai
{

public void teste()
{
     System.out.println("teste");		
}

public static void esseMetodo()
{
	System.out.println("Classe PAI");
}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////

public class Concreta extends ClassePai{

public Concreta()
{
	
}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////

public class PolymorphismTest
{

public static void main(String args[])
{

	Concreta.esseMetodo();
}

}

////////////////////////////////////////////////////////////////////////////////////////////////////////

Então porque em minha classe PolymorphismTest, a classe Concreta que herda da ClassePai, consegue chamar um método static que não foi declarado nela, mas sim herdado da classe ClassePai não?? Pelo que sei na herança uma classe herda as funcionalidade de outra classe.

sergiotaborda - estou falando isso na boa, espero que você não leve a mal.

[quote=kakabill]

Então porque em minha classe PolymorphismTest, a classe Concreta que herda da ClassePai, consegue chamar um método static que não foi declarado nela, mas sim herdado da classe ClassePai não?? Pelo que sei na herança uma classe herda as funcionalidade de outra classe.

sergiotaborda - estou falando isso na boa, espero que você não leve a mal.[/quote]

Não, como levaria a mal ? :wink:

O problema é que vc está chamando shawdoing de herança. O método é acessivel através das filhas, mas não é modificável pelas filhas, logo não ha herança nesta historia. Para haver herança tem que haver possibilidade de modificar o comportamento.

eu entendi o que você está querendo dizer, eu sei o que é sobrecarga, não estava falando dela hora nenhuma. É porque pensei o seguinte, a herança diz que uma classe herda, deriva as funcionalidades, uma subclasse herda um metodo static, mas não pode sobrescrever ele. Um metodo static é resolvido em tempo de compilação não é? Deve ser por isso que não pode ser modificado pela subclasse, mas eu acho que herda, estamos tendo opiniões diferentes :confused: .

Foi porque pensei que como sou novo nesse forum, estava indo com muita sede ao pote, kkkkk, de boas então.

[quote=kakabill]eu entendi o que você está querendo dizer, eu sei o que é sobrecarga, não estava falando dela hora nenhuma.
[/quote]

Nem eu…

Vou tentar deixar as coisas mais claras.
Temos 3 conceitos em jogo aqui: Acessibilidade , Shawdoing (sombreamento ) e Herança.

O que é shadowing ?
Shadowing (sombreamento) é um tipo de polimorfismo estático e é possível graças ao conceito de escopo.
É tomar em consideração que a acessibilidade de um artefato (método, variável, classe, etc) depende de um escopo. Por isso eu posso definir nomes iguais para coisas diferentes. Elas são diferentes, se têm um nome diferente (uma identidade diferente) ou se têm um escopo diferente.


class X {

  int m =1 ; 


  public int getN(){
          int m = 2;
        return m;
  } 
} 

O resultado de invocar x.getN() é 2. Porquê ? Por causa do sobreamento.
Ao definir m dentro do método , estou definido o simbolo m num escopro mais próximo do método do que aquele que que é definido na classe. (estou ponto o m da classe à sobra do m do método. )

Isto ilustra bem que shawdoing nada tem a haver, diretamente, com herança. Também não tem nada a haver com sobrecarga nem sobrescrita.
Contudo, o sobreamento é o que me permite definir dois atributos com nome igual em classes da mesma hierarquia. Assim


class A {

  int n=3;

  public int getN(){
        return n;
  }
}

class B {

  int n=4;

  public int getN(){
        return n;
  }
}

class C {

  int n=5;

  public int getN(){
        return super.n;
  }
}

Quando eu invocar b.getN() o resultado será 4, Mas quando invocar c.getN() será 3. Isto pode ser um problema se não se tomar atenção.

Então, como o Java sabe o que tem que invocar quando encontra um simbolo de um artefato (n , no caso) ? Ele procura por esse simbolo no escopo mais próximo. Se não encontrar ele vai procurar nos escopo mais afastados até que encontre o simbolo. Quando encontrar ele executa esse simbolo nesse escopo. Se nunca encontrar lança um erro.
Os escopos licitos podem ser modificados com os modificadores de acessibilidade (public, protected, private)

Repare que isto só tem a haver com herança de forma indireta já que herdar é uma forma de criar um escopo diferente. A herança não se aplica para artefatos estáticos mas a regra de invocação sim.

Então o que é herança ?
Herança não tem só a haver com acessibilidade mas tb com reaproveitamento. As propriedades e os comportamentos são reaproveitados, herdados. Mas são os mesmos ? Não.
Herdar significa estender o escopo do filho até à classe pai. Assim , tudo o que for procurado no filho e não for achado, será procurado no pai.
Até aqui nada de especial. Tanto métodos estáticos como não estáticos segue esta regra de procura. A diferença está na outra metade da herança (e por isso se chama herança) O pai pode, explicitamente, delegar para o filho a responsabilidade de implementar um comportamento.
Isto significa que o filho é obrigado a ter o simbolo definido no seu escopo e não pode usar o do pai. Isto se consegue em Java com o modificador abstract.

É esta segunda parte da herança que não está disponivel para coisas estáticas e é por isso que coisas estáticas não são herdadas.
São acessiveis, sim. Porque a acessibilidade funciona de baixo para cima, mas não são herdaveis. A herança funciona de cima para baixo.

Então, o codigo que vc escreveu é completamente compreensivel face a estas regras. E face a estas regras vc não pode dizer que metodos estáticos são heradados pelas classes filhas. O que vc deve dizer é que a classe filha tem acesso aos métodos estáticos do pai , se eles não tiverem sido redefenidos.

Redefinição de métodos estáticos é a mesma coisa que sobrescrita de métodos ? Não.
Porquê ? Porque sobrescrever significa , claro, escrever sobre. Ou seja, quando eu sobrescrevo o método original ainda existe. Eu ainda tenho acesso a ele. É como ter um texto no papel e sobrescrever algumas palavras e outras não. O texto oiriginal ainda está lá.
Como eu sei ? Porque eu posso invocar super.metodo()
Redefenir é simplesmente deitar fora o original e escrever outro. A diferença ? Não dá mais para chamar super.metodo()

Esta é a diferença: Métodos estáticos são redefinidos pelas classes filhas, não sobrescritos nem sobrecarregados. Sobrecarga é, ainda, outra coisa.

Então que fique claro:

  1. Métodos estáticos não são herdáveis nem sobrescritos. A prova é que não posso chamar super.metodo().
  2. Métodos estáticos são acessíveis por subclasses, da mesma forma que qualquer outro artefato. Isto não tem nada a ver com herança e sim com acessibilidade e polimorfismo estático.
    2.1) Se um filho redefine um métodos estático do pai, ele está escondendo o acesso ao método pai. A isto se chama sobreamento ( Shadowing)
    2.2) Shawdoing é um conceito de polimorfismo estático que não tem nada a ver com herança.
  3. Herança é uma forma de estender o escopo da classe a uma outra classe dita superior (dai(?) a lógica palavra extends para definir herança e não inherits )
  4. Sobrescrever, sobrecarregar e redefinir são 3 operações diferentes que se podem fazer a um método, sendo que a redefinição só acontece para métodos estáticos e as sobrescrita para métodos herdados.

Não é uma questão de nomes, é uma questão de conceitos. Espero que isto tenha ajudado a esclarecer as coisas.

sergiotaborda,

kra… belíssima, perfeita.

Parabéns é pouco por essa aula.

É como eu havia dito kakabill, porém de forma bem menos detalhada, vc pode redefinir um método, mas nunca sobrescrever.

é bem simples na verdade:

você nao herda o metodo estatico, porque ele pertence a classe e não ao objeto, mas o porque de voce pensar que ele pertence ao objeito, que foi herdado, e porque voce consegue invocar o metodo estatico atraves do seu objeto filho, certo ?
atraves de um objeto.metodoEstatico();

mas oque acontece e que a jvm sabe que seu objeito ta referenciando uma classe que possui este metodo estatico, logo permite que voce chame tanto o metodo pelo seu objeito quanto pelo nome real da classe… , ou seja e so pra poupar trabalho ( e complicar a cabeca)

explicando em codigo:

class A {
public static void say() 
{
System.out.println("meotod estatico da classe A");
}
}
class B  extends A {
public static void main ( String [] a ) 
{
B teste = new B();
teste.say(); // parece que herdou ne?   // na verdade essa linha seria B.say();
              // mas na verdade oque acontece aqui a JVM le aqui e assim
              // "JVM" -> bom ele nao especificou a classe que quer executar o metodo
              // statico mas como eu sou uma JVM esperta vou descobri atraves da variavel
              // de refencia teste quem ela ta instanciando ai posso chamar diretamente o               
              // B.say();
}

sei que muitos ja explicaram mas como eu sou meio novato, e to estudando pra certifacação resolvi explicar do meu jeito newbie de ser =D, que eu acho facil de intender.

sergiotaborda, me desculpe estava viajando, mas no instante que cheguei logo entrei neste fórum para ver sua resposta, muito bom cara, aprendi coisas novas que sanaram algumas dúvidas minhas.

Parabéns, se cuida e até a próxima.

Excelente explicação do sergio taborda.

Estava exatamente com as mesmas dúvidas.

Recomendo este post a todos que vão prestar a prova scjp.

Valeu!!!

:smiley: