Lucas, eu acho que quando ele perguntou sobre acessar atributos, ele quis dizer algo assim:
public class App {
public static void main(String... args) {
class Funcionario {
int umAtributoQualquer = 123;
}
class Diretor extends Funcionario {
int umAtributoQueSoDiretorTem = 456;
}
Funcionario sandro = new Diretor();
System.out.println(sandro.umAtributoQueSoDiretorTem);
}
}
Se for isso mesmo do caso acima, vc não vai conseguir, pois dá erro de compilação.
Para acessar membro da subclasse, vc teria que fazer um casting:
System.out.println( ((Diretor) sandro).umAtributoQueSoDiretorTem );
Eu imagino que isso pareça estranho para vc, afinal “está óbvio que sandro
é um Diretor
, então como o compilador não consegue ver isso???”.
O ponto é que seu exemplo é simples demais e para fazer mais sentido vc precisa imaginar situações mais complexas.
Imagine que vc tem um programa grandinho, dividido em vários pacotes e num pacote vc tem isto:
package escola;
abstract class Funcionario {
abstract void pagar();
}
class Escola {
void pagarFuncionarios(Funcionario[] funcionarios) {
for(int i = 0; i < funcionarios.length; i++) {
funcionarios[i].pagar();
}
}
}
A classe Escola
não tem como saber se o array funcionarios
contém algum Diretor
, ou Professor
ou Faxineiro
. Na verdade, para ela nada importa isso, só o que importa é que sejam Funcionario
e assim implementem o método pagar()
.
Como uma linguagem de tipagem forte, o Java se importa muito com os tipos e exige que vc seja bem explícito quando quiser fazer a conversão de um tipo para outro compatível, é o caso do uso do cast, em código ele fica feio já pra ficar bem destacado a intenção do programador.
Agora imagine como seria ruim se vc tivesse um método pagarFuncionarios()
para cada tipo de funcionário que tem na sua escola!
class Escola {
void pagarDiretor(Diretor[] diretores) {
for(int i = 0; i < diretores.length; i++) {
diretores[i].pagar();
}
}
void pagarProfessor(Professor[] professores) {
for(int i = 0; i < professores.length; i++) {
professores[i].pagar();
}
}
void pagarFaxineiro(Faxineiro[] faxineiros) {
for(int i = 0; i < faxineiros.length; i++) {
faxineiros[i].pagar();
}
}
}
Não faria sentido ter todo este trabalho se todos possuem o método pagar()
. Neste caso, ter Funcionario
como superclasse ajuda bastante.
Estes são exemplos bobos, as coisas ficarão mais claras conforme vc aprender mais e botar em prática numa aplicação real.
Sobre sua dúvida a respeito das 2 referências, complementando o que o Lucas disse, vc tem que pensar que, para todos os efeitos, Diretor
é um Funcionario
.