SOBREPOSIÇÃO/SOBRESCRIÇÃO

Todas as vezes que se tiver uma classe que herde um método da super classe, poderá sobrescrever esse método, a menos que ele tenha sido declarado como final. Observe o exemplo a seguir.


        package devmedia;

        class A{
        String getName(){
        return "A";
        }
        }
        class B extends A{
        String getName(){
        return "B";
        }
        }
        public class Main {

        public static void main(String[] args) {
        A a = new A();
        System.out.println(a.getName());
        B b = new B();
        System.out.println(b.getName());
        A ab = new B();
        System.out.println(ab.getName());

        }

        }
        

Saída:
A
B
B

O principal benefício da sobreposição é a possibilidade de escrever um determinado comportamento específico de um tipo de subclasse.

Um outro exemplo de polimorfismo é mostrado abaixo:


        package devmedia;

        abstract class Automovel{
        public abstract void aumentarVelocidade();
        }
        class Fusca extends Automovel{
        public void aumentarVelocidade(){
        System.out.println("Acelerando o Fusca!");
        }
        }
        class Ferrari extends Automovel{
        public void aumentarVelocidade(){
        System.out.println("Voando na Ferrari!");
        }
        }

        public class TestePolimorfismo {
        public static void main(String args[]){
        Automovel fusca = new Fusca();
        Automovel ferrari = new Ferrari();
        fusca.aumentarVelocidade();
        ferrari.aumentarVelocidade();
        }
        }
        

Saída:
Acelerando o Fusca!
Voando na Ferrari!

O novo método, no caso o método aumentarVelocidade() da subclasse, não poderá ter um modificador de acesso que seja mais restritivo do que o método que foi sobrescrito.

O que proporciona a possibilidade dessa superclasse referenciar uma instância da subclasse é a certeza de que a subclasse pode executar tudo o que a superclasse pode executar.

REGRAS PARA A SOBRESCRITA DE UM MÉTODO

A lista de argumentos deve coincidir como a do método sobrescrito. O tipo de retorno deve ser idêntico, ou subtipo, do tipo de retorno marcado no método original da superclasse.

O nível de acesso não pode ser mais restritivo do que o do método sobrescrito. O nível de acesso pode até ser menos restritivo que o do método original.

Os métodos de instâncias apenas podem ser sobrescritos se forem herdados pela subclasse. Uma subclasse do mesmo pacote que a superclasse é capaz de sobrescrever qualquer método da superclasse, desde que o método não seja declarado como final ou private.

Uma subclasse de um pacote diferente apenas pode sobrescrever os métodos não-final marcados como protected ou public, uma vez que os métodos protected são herdados pela subclasse.

O método sobrescrito pode lançar qualquer exceção não-verificada, independentemente de um método sobrescrito declarar ou não a exceção.

O método novo não pode lançar exceções verificadas novas, ou mais abrangentes, do que as marcadas pelo método sobrescrito. Exemplificando, um método que declare uma exceção verificada do tipo FileNotFoundException não poderá ser sobrescrito por um método que declare uma Exception, SQLException, ou qualquer outra exceção que não seja uma subclasse de FileNotFoundException.

Não é possível também sobrescrever um método marcado como static. Se um método não poder ser herdado, não poderá ser sobrescrito.

INVOCANDO A VERSÃO DA SUPERCLASSE DE UM MÉTODO SOBRESCRITO

Normalmante, você irá se beneficiar de algum código da superclasse para um método e ainda assim sobrescrevê-lo para fornecer um comportamento mais especifico.

É notório ressaltar que não é preciso que a versão da superclasse seja executada antes do código da subclasse.


        package devmedia;
        class Funcionario{
        private String primeiroNome = "Davi";
        private String ultimoNome = "Costa";

        public String toString(){
        return primeiroNome+" "+ultimoNome;
        }
        }
        class Chefe extends Funcionario{
        private int area = 7;

        public String toString(){
        return super.toString()+" Área - "+area;
        }
        }

        public class Example {
        public static void main(String args[]){
        Funcionario f = new Chefe();
        System.out.println(f.toString());
        }
        }
        

Saída:
Davi Costa Área - 7

A sobrecarga de métodos proporciona que você utilize métodos com o mesmo nome, em cada classe, mas com outros argumentos e, opcionalmente, um tipo de retorno diferente.

As regras são bem simples: os métodos sobrecarregados podem alterar o tipo de retorno, os métodos sobrecarregados devem alterar a lista de argumentos (assinatura), os métodos sobrecarregados podem mudar o modificador de acesso, os métodos sobrecarregados podem declarar exceções mais abrangentes ou verificadas novas. Analise o próximo exemplo:


        package devmedia;
        class Sobre{
        public void metodoX(int a, int b){
        System.out.println("Sobrecarga 2 ints");
        }
        public void metodoX(int a, String b){
        System.out.println("Sobrecarga 1 int, 1 String");
        }
        protected String metodoX(String a, int b){
        System.out.println("Sobrecarga 1 String, 1 int");
        return "Modificou o tipo de retorno";
        }
        void metodoX(int a, int b, int c){
        System.out.println("Sobrecarga 3 ints");
        }
        }
        class SobreII extends Sobre{
        void metodoX(int a, int b, String c){
        System.out.println("Sobrecarga 2 ints, 1 String");
        }
        }
        public class TesteSobrecarga {
        public static void main(String args[]){
        Sobre x = new Sobre();
        x.metodoX(15, 16);
        x.metodoX(15, "texto");
        x.metodoX("texto", 16);
        x.metodoX(1, 2, 3);

        SobreII y = new SobreII();
        y.metodoX(15, 16);
        y.metodoX(15, "texto");
        y.metodoX("texto", 16);
        y.metodoX(1, 2, 3);
        y.metodoX(1, 2, "texto");

        Sobre z = new SobreII();
        //z.metodoX(1, 2, "texto"); não compila
        }
        }
        

Saída:
Sobrecarga 2 ints
Sobrecarga 1 int, 1 String
Sobrecarga 1 String, 1 int
Sobrecarga 3 ints
Sobrecarga 2 ints
Sobrecarga 1 int, 1 String
Sobrecarga 1 String, 1 int
Sobrecarga 3 ints
Sobrecarga 2 ints, 1 String

A sobrescrição/sobreposição depende do tempo de execução; entretanto, a sobrecarga depende do tempo de compilação, em outras palavras, do ponto da referência e não do tipo de objeto. Porém, algumas vezes um método é sobrescrito e sobrecarregado. Veja que a classe Macaco tanto sobrepôs quanto sobrescreveu o método alimentar(). Iremos analisar as possibilidades.


        package devmedia;

        class Mamifero{
        public void alimentar(){
        System.out.println("Mamífero alimentado");
        }
        }
        class Macaco extends Mamifero{
        public void alimentar(){
        System.out.println("Macaco alimentado");
        }
        public void alimentar(String texto){
        System.out.println("Macaco bem alimentado");
        }
        }
        public class Teste {
        public static void main(String args[]){
        Mamifero mamifero = new Mamifero();
        mamifero.alimentar();

        Macaco macaco = new Macaco();
        macaco.alimentar();

        Mamifero mm = new Macaco();
        mm.alimentar();
        macaco.alimentar("Sobrecarga");
        }
        }
        

Saída:
Mamífero alimentado
Macaco alimentado
Macaco alimentado
Macaco bem alimentado

Na última parte do artigo abordaremos conceitos de variável de referência, construtores, modificador static, acoplamento/coesão, coleta de lixo e aplicaremos um mini-teste.


Leia todos artigos da série