Achei esse exemplo na Internet e gostaria de saber porquê ao rodar o programa ele imprime Writing e não Writing Code?
abstract class Writer {
public static void write() {
System.out.println(“Writing…”);
}
}
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();
}
}
Então ele deveria imprimir o que está definido no método write em Programmer que não é o caso.
Métodos statics são da classe e não do objeto:
abstract class Writer {
public static void write() {
System.out.println("Writing…");
}
public static void writeChar(char c) {
System.out.println("Writing… " + c);
}
}
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(); // Writing… (da classe Writer, pois w é do tipo Writer)
Programmer p = (Programmer) w;
p.write(); // Writing code (da classe Programmer, pois p é do tipo Programmer)
p.writeChar('A'); // Writing… A (da classe Writer, pois Programmer não tem esse método)
}
}
Se os métodos não fossem statics a saída seria:
Writing code
Writing code
Writing… A
O comportamento difere entre métodos de classe e métodos de instancia.
É dito que um método de instancia é sobreescrito (overriding) enquanto que um método de classe é apenas escondido (hiding).
Você pode ler mais detalhes aqui:
https://docs.oracle.com/javase/tutorial/java/IandI/override.html
E aqui:
https://docs.oracle.com/javase/specs/jls/se10/html/jls-8.html#jls-8.4.8
Mas em resumo:
- Um método de classe é invocado com base no tipo da variável que o contém.
- Um método de intancia é invocado com base no tipo do objeto instanciado nesta variável.
Sendo assim:
class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
public void testInstanceMethod() {
System.out.println("The instance method in Animal");
}
}
class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public void testInstanceMethod() {
System.out.println("The instance method in Cat");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
myAnimal.testClassMethod(); // "The static method in Animal"
myAnimal.testInstanceMethod(); // "The instance method in Cat"
// Para invocar o estático de Cat, só com casting
((Cat) myAnimal).testClassMethod(); // "The static method in Cat"
}
}
De qualquer forma, é recomendado que ao acessar métodos estáticos, use o nome da classe e não do objeto. Ou seja:
Writer.write();
// ou
Programmer.write();
Ao invés de:
new Writer().write();
// ou
new Programmer().write();
Obs: Ao postar código, utilize as tags corretas para melhor visualização de todos. Em caso de duvidas, este tópico pode ajudar.