Em Java, a palavra-chave extends etsabelece uma relação de herança entre classes, permitindo que uma classe filha herde membros não privados da classe pai.
package pacote_heranca;
public class Pessoa {
private String nome;
private int idade;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getIdade() {
return idade;
}
public void setIdade(int idade) {
this.idade = idade;
}
}
package pacote_heranca;
public class Estudante extends Pessoa {
private String instituicao;
public String getInstituicao() {
return instituicao;
}
public void setInstituicao(String instituicao) {
this.instituicao = instituicao;
}
}
Os modificadores de acesso definem a visibilidade dos membros. private restringe o acesso à própria classe. protected permite acesso na classe, no mesmo pacote e em subclasses. A herança em Java é única, sem suporte a herança múltipla. Todas as classes herdam diretamente ou indiretamente da classe Object. Ao acessar membros, a regra de proximidade se aplica: primeiro busca na clasce filha, depois na pai. Para acessar membros da classe pai com o mesmo nome, usa-se super, como em super.nome.
A sobrescrita de métodos ocorre quando a classe filha redefine um método da classe pai. O nome e os parâmetros devem ser idênticos.
package pacote_heranca;
public class Pessoa {
public void exibirRenda() {
System.out.println("renda");
}
}
package pacote_heranca;
public class Estudante extends Pessoa {
@Override
public void exibirRenda() {
System.out.println("renda atualizada");
}
}
A anotação @Override indica que o método está sendo sobrescrito. As regras incluem: a visibilidade do método sobrescrito deve ser igual ou maior que a da classe pai; o tipo de retorno deve ser igual ou mais restrito; métodos privados e estáticos não podem ser sobrescritos.
Construtores em classes filhas sempre invocam o construtor da classe pai primeiro. Por padrão, super() é chamado implicitamente. Se a classe pai não tiver um construtor sem parâmetros, é necessário especificar um construtor com parâmetros usando super(parametros).
package pacote_heranca;
public class Pessoa {
public Pessoa(int valor) {
// lógica do construtor
}
}
package pacote_heranca;
public class Estudante extends Pessoa {
public Estudante() {
super(10);
}
}
Dentro de um construtor, this() pode ser usado para chamar outros construtores da mesma classe, mas deve ser a primeira instrução.
package pacote_heranca;
public class Estudante {
private String nome;
private int idade;
private double altura;
private String genero;
public Estudante(String nome, int idade, double altura) {
this(nome, idade, altura, "Masculino");
}
public Estudante(String nome, int idade, double altura, String genero) {
this.nome = nome;
this.idade = idade;
this.altura = altura;
this.genero = genero;
}
}
package pacote_heranca;
public class Principal {
public static void main(String[] args) {
Estudante s1 = new Estudante("Carlos", 20, 1.80);
Estudante s2 = new Estudante("Ana", 22, 1.65, "Feminino");
}
}
O polimorfismo surge em contextos de herança ou implementação, permitindo que objetos de diferentes classes sejam tratados como objetos de uma classe comum. Isso se aplica a objetos e comportamentos, não a atributos.
package pacote_heranca;
public class Pessoa {
public void estudar() {
System.out.println("estudando");
}
}
package pacote_heranca;
public class Estudante extends Pessoa {
@Override
public void estudar() {
System.out.println("aprendendo");
}
}
package pacote_heranca;
public class Professor extends Pessoa {
public void estudar() {
System.out.println("ensinando");
}
}
package pacote_heranca;
public class Principal {
public static void main(String[] args) {
Pessoa p1 = new Estudante();
Pessoa p2 = new Professor();
p1.estudar();
p2.estudar();
}
}
Uma limitação do polimorfismo é que não é possível acessar métodos exclusivos da classe filha sem uma conversão de tipo. A conversão automática ocorre ao atribuir um objeto da classe filha a uma referência da classe pai. A conversão explícita é necessária para acessar membros da classe filha.
package pacote_heranca;
public class Estudante extends Pessoa {
@Override
public void estudar() {
System.out.println("aprendendo");
}
public void irParaEscola() {
System.out.println("indo para a escola");
}
}
package pacote_heranca;
public class Principal {
public static void main(String[] args) {
Pessoa p1 = new Estudante();
p1.estudar();
Estudante e1 = (Estudante) p1;
e1.irParaEscola();
}
}
A conversão explícita é válida se houver relação de herança, mas em tempo de execução, se o tipo real do objeto não corresponder, uma exceção será lançada.
A palavra-chave final pode ser aplicada a classes, métodos e variáveis. Classes finais não podem ser herdadas. Métodos finais não podem ser sobrescritos. Variáveis finais são constantes após a primeira atribuição. Para tipos primitivos, o valor não pode mudar; para referências, o endereço é fixo, mas o conteúdo pode ser alterado. Constantes são declaradas com static final e nomes em maiúsculas.
O padrão Singleton garante que uma classe tenha apenas uma instância. Para implementar: declare o construtor como privado, armazene uma instância estática e forneça um método estático para obtê-la.
package padroes;
public class Unico {
private static Unico instancia = new Unico();
private Unico() {
}
public static Unico obterInstancia() {
return instancia;
}
}
package padroes;
public class Principal {
public static void main(String[] args) {
Unico u1 = Unico.obterInstancia();
Unico u2 = Unico.obterInstancia();
// u1 e u2 referenciam o mesmo objeto
}
}
Classes de enumeração (enum) definem um conjunto fixo de constantes. A primeira linha declara as constantes, que são instâncias da enumeração. Enums são implicitamente finais e seus construtores são privados.
package enumeracoes;
public enum DiaSemana {
SEGUNDA, TERCA, QUARTA;
}
package enumeracoes;
public class Principal {
public static void main(String[] args) {
DiaSemana dia1 = DiaSemana.SEGUNDA;
DiaSemana dia2 = DiaSemana.TERCA;
DiaSemana dia3 = DiaSemana.QUARTA;
}
}
Classes abstratas são definidas com abstract e podem conter métodos abstratos, que são declarados sem implementação. Classes abstratas não podem ser instenciadas e servem como base para subclasses que implementam seus métodos.
package abstracao;
public abstract class Forma {
public abstract void desenhar();
}