Polimorfismo vs Substituição vs Sobrecarga

347

Em termos de Java, quando alguém pergunta:

o que é polimorfismo?

Iria sobrecarregar ou substituindo ser uma resposta aceitável?

Eu acho que há um pouco mais do que isso.

Se você tinha uma classe base abstrata que definiu um método sem implementação e definiu esse método na subclasse, isso ainda está substituindo?

Eu acho que sobrecarregar não é a resposta certa, com certeza.

Brian G
fonte
As respostas abaixo explicam muito bem o polimorfismo. Mas tenho forte objeção a dizer que a sobrecarga é um tipo de polimorfismo, que tentei justificar na minha pergunta e resposta que realmente se concentra na sobrecarga é polimorfismo ou não. Tentei justificar a resposta do @The Digital Gabeg presente neste tópico. Refer Elaboration: A sobrecarga de método é uma ligação estática / em tempo de compilação, mas não um polimorfismo. É correto correlacionar a ligação estática com o polimorfismo?
PraveenKumar Lalasangi

Respostas:

894

A maneira mais clara de expressar o polimorfismo é através de uma classe base abstrata (ou interface)

public abstract class Human{
   ...
   public abstract void goPee();
}

Esta classe é abstrata porque o goPee()método não é definível para seres humanos. É apenas definível para as subclasses Macho e Fêmea. Além disso, humano é um conceito abstrato - você não pode criar um humano que não seja masculino nem feminino. Tem que ser um ou outro.

Portanto, adiamos a implementação usando a classe abstrata.

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

e

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

Agora podemos dizer a uma sala inteira cheia de humanos para fazer xixi.

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

Executar isso renderia:

Stand Up
Sit Down
...
Chris Cudmore
fonte
37
@yuudachi. Eu vim com esse exemplo ao dar uma aula. A classe canônica "Conta bancária" não expressou realmente a "abstração" da classe base. O outro exemplo canônico (Animal, faça barulho) era abstrato demais para a compreensão. Eu estava procurando uma única base com subclasses muito óbvias. Na verdade, goPee () foi o único exemplo que inventei que não era sexista ou estereotipado. (embora em sala de aula, eu impresso "pelo corredor à esquerda" em vez de ficar de pé ou sentar-se.)
Chris Cudmore
100
Este exemplo também destaca bem a dificuldade de usar um sistema hierárquico para descrever sistemas biológicos. Alguns seres humanos, como os muito jovens, fazem xixi em quase qualquer posição - e os bebês não podem ser facilmente instruídos a fazer xixi (). Alguns seres humanos são intersexuais, onde os rótulos biológicos de "masculino" ou "feminino" se tornam bastante mal definidos; os significados sociais são ainda mais complexos. Como exemplo de ensino, mostra como as suposições de modelagem podem ter resultados negativos, como a implicação de que alguém (por exemplo, um aluno de programação OO) que é incontinente ou intersexo não é realmente humano.
Andrew Dalke
7
Posso pensar em pelo menos um punhado de seres humanos que refutariam sua tese "você não pode criar um ser humano que não seja homem nem mulher", embora isso ainda seja verdadeiro para seu código ... má abstração, suponho que esteja dizendo ? ;)
Frank W. Zammetti
2
Eu acho importante ressaltar que é apenas polimorfismo, porque qual versão do goPee () chamar só pode ser determinada em tempo de execução. Embora este exemplo implique isso, é bom ressaltar por que exatamente isso é polimorfismo. Além disso, ele não requer classes de irmãos. Também pode ser um relacionamento pai-filho. Ou mesmo classes completamente independentes, que coincidentemente têm a mesma função. Um exemplo disso pode ser a função .toString (). Que pode ser chamado aleatoriamente em qualquer objeto, mas o compilador nunca pode saber exatamente qual tipo de objeto.
Tor Valamo
20
@AndrewDalke, +1 para notas sobre complexidade biológica. Além disso, goPeenão aceita um campo gravitacional como entrada. Essa dependência do estado global dificulta o teste de unidade CatheterizedIntersexAstronaute mostra que a subclasse nem sempre pode ser o melhor método para a composição de características.
Mike Samuel
99

Polimorfismo é a capacidade de uma instância de classe se comportar como se fosse uma instância de outra classe em sua árvore de herança, geralmente uma de suas classes ancestrais. Por exemplo, em Java todas as classes herdam de Object. Portanto, você pode criar uma variável do tipo Object e atribuir a ela uma instância de qualquer classe.

Uma substituiçãoé um tipo de função que ocorre em uma classe que herda de outra classe. Uma função de substituição "substitui" uma função herdada da classe base, mas o faz de tal maneira que é chamada mesmo quando uma instância de sua classe está fingindo ser um tipo diferente por meio do polimorfismo. Referindo-se ao exemplo anterior, você pode definir sua própria classe e substituir a função toString (). Como essa função é herdada de Object, ainda estará disponível se você copiar uma instância dessa classe em uma variável do tipo Object. Normalmente, se você chamar toString () na sua classe enquanto ela estiver fingindo ser um Objeto, a versão do toString que realmente será acionada será a definida no próprio Objeto. No entanto, como a função é uma substituição, a definição de toString () da sua classe é usada mesmo quando a instância da classe '

Sobrecarregar é a ação de definir vários métodos com o mesmo nome, mas com parâmetros diferentes. Não está relacionado à substituição ou ao polimorfismo.

The Digital Gabeg
fonte
8
Isso é antigo, mas o polimorfismo não implica que a outra classe deva estar na árvore de herança. Isso ocorre em Java se você considerar as interfaces como parte da árvore de herança, mas não no Go, onde as interfaces são implementadas implicitamente.
JN
5
Na verdade, você não precisa de aulas de polimorfismo.
StCredZero
3
Sou novato e me corrija se estiver errado, mas não diria que a sobrecarga não está relacionada ao polimorfismo. Pelo menos em Java, polimorfismo é quando a implementação é escolhida com base no tipo de chamador e sobrecarga é quando a implementação é escolhida com base no tipo de parâmetros, não é? Ver a semelhança entre os dois me ajuda a entender.
csjacobs24
9
Incorreta. Ad hoc polymorphismé o que você descreveu na seção Sobrecarga e é um caso de polimorfismo.
Jossie Calderon
11
"Não está relacionado à substituição ou ao polimorfismo". Esta afirmação está errada.
Shailesh Pratapwar
45

Polimorfismo significa mais de uma forma, o mesmo objeto executando operações diferentes de acordo com o requisito.

O polimorfismo pode ser alcançado usando duas maneiras, essas são

  1. Substituição de método
  2. Sobrecarga de método

Sobrecarga de método significa escrever dois ou mais métodos na mesma classe usando o mesmo nome de método, mas os parâmetros de passagem são diferentes.

Substituição de método significa que usamos os nomes de método nas diferentes classes, ou seja, o método da classe pai é usado na classe filho.

Em Java, para obter polimorfismo, uma variável de referência de superclasse pode conter o objeto de subclasse.

Para atingir o polimorfismo, todo desenvolvedor deve usar o mesmo nome de método no projeto.

manoj
fonte
4
+1 para uma boa resposta. A resposta aceita explica apenas um tipo de polimorfismo. Esta resposta está completa.
Apadana 15/07/2015
11
O polimorfismo é um paradigma (POO), mas a substituição e a sobrecarga são facilidades de linguagem.
曾其威
O polimorfismo também pode ser alcançado por tipo genérico.
Minh Nghĩa
43

Aqui está um exemplo de polimorfismo no pseudo-C # / Java:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

A função Main não conhece o tipo do animal e depende do comportamento de uma implementação específica do método MakeNoise ().

Edit: Parece que Brian me venceu no soco. Engraçado, usamos o mesmo exemplo. Mas o código acima deve ajudar a esclarecer os conceitos.

Mark A. Nicolosi
fonte
É um exemplo de polimorfismo em tempo de execução. O polimorfismo em tempo de compilação também é possível através da sobrecarga de métodos e tipos genéricos.
Pete Kirkham
Forma -> Paralelogramo -> Retângulo -> Quadrado
mpen
@ yankee2905, neste caso, acho que você poderia usar interfaces, já que uma classe poderia implementar várias interfaces.
precisa saber é o seguinte
11
@Zhisheng Ou adicionando um método xixi na classe pai abstrata? Eu usaria a interface para implementar outra coisa.
Joey Rohan
42

Tanto a substituição quanto a sobrecarga são usadas para alcançar o polimorfismo.

Você pode ter um método em uma classe que é substituída em uma ou mais subclasses. O método faz coisas diferentes, dependendo de qual classe foi usada para instanciar um objeto.

    abstract class Beverage {
       boolean isAcceptableTemperature();
    }

    class Coffee extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature > 70;
       }
    }

    class Wine extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature < 10;
       }
    }

Você também pode ter um método sobrecarregado com dois ou mais conjuntos de argumentos. O método faz coisas diferentes com base no (s) tipo (s) de argumento (s) passado (s).

    class Server {
        public void pour (Coffee liquid) {
            new Cup().fillToTopWith(liquid);
        }

        public void pour (Wine liquid) {
            new WineGlass().fillHalfwayWith(liquid);
        }

        public void pour (Lemonade liquid, boolean ice) {
            Glass glass = new Glass();
            if (ice) {
                glass.fillToTopWith(new Ice());
            }
            glass.fillToTopWith(liquid);
        }
    }
Patrick McElhaney
fonte
Suponho que foi rejeitado porque historicamente a sobrecarga de método não é considerada como parte do polimorfismo no paradigma orientado a objetos. Sobrecarga de método e polimorfismo são dois recursos independentes ortogonais de uma linguagem de programação.
Sergio Acosta
7
Como afirmei na minha resposta aqui, discordo - os dois recursos não são ortogonais, mas estão intimamente relacionados. Polimorfismo! = Herança. Você tem meu voto positivo.
Peter Peter Meyer
2
Em outras palavras, digite polimorfismo vs. polimorfismo ad-hoc. Estou votando positivamente nesta resposta, mesmo que não seja tão completa quanto deveria, porque afirma corretamente que tanto a sobrecarga quanto a substituição estão relacionadas ao polimorfismo. Dizer que o polimorfismo nas linguagens OOP só pode ser alcançado pela herança de classe é simplesmente errado - devemos lembrar que existem outras linguagens OOP além do Java e C ++, onde é possível usar conceitos como despacho múltiplo, polimorfismo ad hoc, polimorfismo paramétrico e assim por diante. .
rsenna
2
@rsenna Isso pode estar incompleto, mas responde à pergunta muito melhor do que o resto do IMHO. Além disso, é muito bom que você tenha mencionado o polimorfismo ad-hoc e paramétrico.
Valentin Radu
15

Você está certo de que sobrecarregar não é a resposta.

Nem é substituindo. Substituir é o meio pelo qual você obtém polimorfismo. Polimorfismo é a capacidade de um objeto variar o comportamento com base em seu tipo. Isso é melhor demonstrado quando o chamador de um objeto que exibe polimorfismo não tem conhecimento do tipo específico de objeto.

Alex B
fonte
3
Não deve ser o comportamento do objeto que muda, mas sua implementação. Mesmo comportamento, implementação diferente, isso é polimorfismo.
QBziZ 30/09/08
@QBziZ Você precisa definir o comportamento , especialmente o mesmo adjetivo . Se o comportamento for o mesmo, por que sua implementação deve ser diferente? Não é que alguém esteja insatisfeito com uma determinada implementação; portanto, é necessária outra.
21716
11

Especificamente, dizer sobrecarregar ou substituir não fornece uma imagem completa. Polimorfismo é simplesmente a capacidade de um objeto de especializar seu comportamento com base em seu tipo.

Eu discordo de algumas das respostas aqui em que a sobrecarga é uma forma de polimorfismo (polimorfismo paramétrico) no caso em que um método com o mesmo nome pode se comportar de maneira diferente, fornecendo diferentes tipos de parâmetros. Um bom exemplo é a sobrecarga do operador. Você pode definir "+" para aceitar diferentes tipos de parâmetros - digamos strings ou int's - e com base nesses tipos, "+" se comportará de maneira diferente.

O polimorfismo também inclui métodos de herança e substituição, embora possam ser abstratos ou virtuais no tipo base. Em termos de polimorfismo baseado em herança, Java suporta apenas herança de classe única, limitando seu comportamento polimórfico ao de uma única cadeia de tipos de base. Java suporta a implementação de várias interfaces, que é outra forma de comportamento polimórfico.

Peter Meyer
fonte
Você está certo em termos do que as palavras envolvidas significam em geral, mas em um contexto de programação, quando as pessoas dizem "polimorfismo", elas sempre significam "polimorfismo baseado em herança". Ponto interessante, mas acho que descrever o polimorfismo dessa maneira confunde as pessoas.
The Digital Gabeg
Pode ser mais fácil explicar o polimorfismo apenas em termos de herança, mas da maneira como essa pergunta em particular foi feita, acho prudente descrever também o polimorfismo paramétrico.
Patrick McElhaney
4
Para ser claro, acho que as diferentes formas devem ser declaradas - o que eu nem sequer fiz adequadamente - porque existem algumas respostas aqui apresentadas como absolutas. Discordo respeitosamente que no "contexto do programador ... 'polimorfismo' sempre significa 'polimorfismo baseado em herança'"
Peter Meyer
2
Eu acho que a sobrecarga é melhor classificado como Ad-hoc_polymorphism en.wikipedia.org/wiki/...
Manu
Costumo concordar com 'The Digital Gabeg' em seguir. Se você está discutindo POO, polimorfismo geralmente significa polimorfismo de subtipo e, se você está discutindo sobre teoria de tipos, significa qualquer tipo de polimorfismo.
Manu
7

Polimorfismo significa simplesmente "Muitas Formas".

Não é necessário herança para alcançar ... pois a implementação da interface, que não é herança, serve a necessidades polimórficas. Indiscutivelmente, a implementação da interface atende às necessidades polimórficas "Melhor" que a herança.

Por exemplo, você criaria uma superclasse para descrever todas as coisas que podem voar? Eu acho que não. Você ficaria melhor servido para criar uma interface que descreve o voo e deixá-lo assim.

Portanto, como as interfaces descrevem o comportamento e os nomes dos métodos descrevem o comportamento (para o programador), não é muito difícil considerar a sobrecarga de método como uma forma menor de polimorfismo.

BillC
fonte
2
Definitivamente a melhor resposta ainda. O polimorfismo pode ser aplicado a todas as construções da linguagem, sejam substantivos (classes) ou verbos (métodos).
Radu Gasler
6

O exemplo clássico, cães e gatos são animais, os animais têm o método makeNoise. Posso iterar através de uma variedade de animais chamando makeNoise para eles e esperar que eles façam a respectiva implementação.

O código de chamada não precisa saber que animal específico eles são.

Isso é o que eu considero polimorfismo.

Brian G
fonte
4

Polimorfismo é a capacidade de um objeto aparecer de várias formas. Isso envolve o uso de herança e funções virtuais para criar uma família de objetos que podem ser trocados. A classe base contém os protótipos das funções virtuais, possivelmente não implementadas ou com implementações padrão conforme o aplicativo exigir, e as várias classes derivadas as implementam de maneira diferente para afetar comportamentos diferentes.

mxg
fonte
4

Nem:

Sobrecarga é quando você tem o mesmo nome de função que usa parâmetros diferentes.

Substituir é quando uma classe filho substitui o método de um pai por um método próprio (isso por si só não constitui polimorfismo).

O polimorfismo é uma ligação tardia, por exemplo, os métodos da classe base (pai) estão sendo chamados, mas não até o tempo de execução o aplicativo saber qual é o objeto real - pode ser uma classe filho cujos métodos são diferentes. Isso ocorre porque qualquer classe filho pode ser usada onde uma classe base é definida.

Em Java, você vê muito polimorfismo com a biblioteca de coleções:

int countStuff(List stuff) {
  return stuff.size();
}

List é a classe base, o compilador não tem idéia se você está contando uma lista vinculada, vetor, matriz ou uma implementação de lista personalizada, desde que ela funcione como uma lista:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

Se você estivesse sobrecarregando, teria:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

e a versão correta de countStuff () seria escolhida pelo compilador para corresponder aos parâmetros.

jpeacock
fonte
4

Embora o polimorfismo já esteja explicado em grandes detalhes neste post, eu gostaria de enfatizar mais por que parte dele.

Por que o polimorfismo é tão importante em qualquer linguagem OOP.

Vamos tentar criar um aplicativo simples para uma TV com e sem herança / polimorfismo. Poste cada versão do aplicativo, fazemos uma pequena retrospectiva.

Supondo que você seja um engenheiro de software de uma empresa de TV e seja solicitado a escrever um software para os controladores de volume, brilho e cor, para aumentar e diminuir seus valores no comando do usuário.

Você começa escrevendo aulas para cada um desses recursos adicionando

  1. set: - Para definir o valor de um controlador (supondo que este tenha código específico do controlador)
  2. get: - Para obter o valor de um controlador (supondo que este tenha código específico do controlador)
  3. ajuste: - Para validar a entrada e definir um controlador (validações genéricas .. independente dos controladores)
  4. mapeamento de entrada do usuário com controladores: - Para obter entrada do usuário e chamar controladores de acordo.

Versão 1 do aplicativo

import java.util.Scanner;    
class VolumeControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV1    {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

/*
 *       There can be n number of controllers
 * */
public class TvApplicationV1 {
    public static void main(String[] args)  {
        VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
        BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
        ColourControllerV1 colourControllerV1 = new ColourControllerV1();


        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println("Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV1.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV1.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV1.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV1.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV1.adjust(5);
                    break;
                }
                case 6: {
                colourControllerV1.adjust(-5);
                break;
            }
            default:
                System.out.println("Shutting down...........");
                break OUTER;
        }

    }
    }
}

Agora você tem nossa primeira versão do aplicativo de trabalho pronta para ser implantada. Hora de analisar o trabalho realizado até agora.

Problemas na versão 1 do aplicativo de TV

  1. O código de ajuste (valor int) é duplicado nas três classes. Você gostaria de minimizar a duplicidade de código. (Mas você não pensou em código comum e o moveu para uma super classe para evitar código duplicado)

Você decide viver com isso desde que seu aplicativo funcione conforme o esperado.

Às vezes, seu chefe volta para você e solicita que você adicione a funcionalidade de redefinição ao aplicativo existente. A redefinição definiria todos os três controladores com seus respectivos valores padrão.

Você começa a escrever uma nova classe (ResetFunctionV2) para a nova funcionalidade e mapeia o código de mapeamento de entrada do usuário para esse novo recurso.

Versão 2 do aplicativo

import java.util.Scanner;
class VolumeControllerV2    {

    private int defaultValue = 25;
    private int value;

    int getDefaultValue() {
        return defaultValue;
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV2   {

    private int defaultValue = 50;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV2    {

    private int defaultValue = 40;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class ResetFunctionV2 {

    private VolumeControllerV2 volumeControllerV2 ;
    private BrightnessControllerV2 brightnessControllerV2;
    private ColourControllerV2 colourControllerV2;

    ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2)  {
        this.volumeControllerV2 = volumeControllerV2;
        this.brightnessControllerV2 = brightnessControllerV2;
        this.colourControllerV2 = colourControllerV2;
    }
    void onReset()    {
        volumeControllerV2.set(volumeControllerV2.getDefaultValue());
        brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
        colourControllerV2.set(colourControllerV2.getDefaultValue());
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV2 {
    public static void main(String[] args)  {
        VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
        BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
        ColourControllerV2 colourControllerV2 = new ColourControllerV2();

        ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV2.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV2.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV2.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV2.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV2.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV2.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV2.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Então você tem seu aplicativo pronto com o recurso Redefinir. Mas agora você começa a perceber que

Problemas no aplicativo de TV versão 2

  1. Se um novo controlador for introduzido no produto, você deverá alterar o código de recurso Redefinir.
  2. Se a contagem do controlador aumentar muito, será difícil manter as referências dos controladores.
  3. O código de recurso de redefinição está fortemente associado ao código de todos os controladores da classe (para obter e definir valores padrão).
  4. A classe de recurso de redefinição (ResetFunctionV2) pode acessar outro método da classe do controlador (ajuste) que é indesejável.

Ao mesmo tempo, você ouve, chefe, que talvez seja necessário adicionar um recurso em que cada um dos controladores, na inicialização, precisa verificar a versão mais recente do driver do repositório de drivers hospedado da empresa via Internet.

Agora você começa a pensar que esse novo recurso a ser adicionado se assemelha ao recurso Redefinir e os Problemas de aplicativo (V2) serão multiplicados se você não fatorar novamente seu aplicativo.

Você começa a pensar em usar herança para tirar proveito da capacidade polimórfica do JAVA e adiciona uma nova classe abstrata (ControllerV3) ao

  1. Declare a assinatura do método get e set.
  2. Contêm a implementação do método de ajuste que foi replicada anteriormente entre todos os controladores.
  3. Declare o método setDefault para que o recurso de redefinição possa ser facilmente implementado, aproveitando o polimorfismo.

Com essas melhorias, você tem a versão 3 do seu aplicativo de TV pronta para você.

Versão do aplicativo 3

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

abstract class ControllerV3 {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
    abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3   {

    private int defaultValue = 25;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
}
class  BrightnessControllerV3  extends ControllerV3   {

    private int defaultValue = 50;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
}
class ColourControllerV3 extends ControllerV3   {

    private int defaultValue = 40;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
}

class ResetFunctionV3 {

    private List<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (ControllerV3 controllerV3 :this.controllers)  {
            controllerV3.setDefault();
        }
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV3 {
    public static void main(String[] args)  {
        VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
        BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
        ColourControllerV3 colourControllerV3 = new ColourControllerV3();

        List<ControllerV3> controllerV3s = new ArrayList<>();
        controllerV3s.add(volumeControllerV3);
        controllerV3s.add(brightnessControllerV3);
        controllerV3s.add(colourControllerV3);

        ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV3.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV3.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV3.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV3.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV3.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV3.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV3.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Embora a maior parte do problema listado na lista de problemas da V2 tenha sido abordado, exceto

Problemas no aplicativo de TV versão 3

  1. A classe de recurso de redefinição (ResetFunctionV3) pode acessar outro método da classe do controlador (ajuste) que é indesejável.

Novamente, você pensa em resolver esse problema, já que agora possui outro recurso (atualização de driver na inicialização) para implementar. Se você não corrigi-lo, ele também será replicado para novos recursos.

Então você divide o contrato definido na classe abstrata e escreve 2 interfaces para

  1. Redefinir recurso.
  2. Atualização do driver.

E faça com que sua 1ª classe concreta os implemente como abaixo

Versão do aplicativo 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface OnReset {
    void setDefault();
}
interface OnStart {
    void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class VolumeControllerV4 extends ControllerV4 {

    private int defaultValue = 25;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for VolumeController .... Done");
    }
}
class  BrightnessControllerV4 extends ControllerV4 {

    private int defaultValue = 50;
    private int value;
    @Override
    int get()    {
        return value;
    }
    @Override
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }

    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for BrightnessController .... Done");
    }
}
class ColourControllerV4 extends ControllerV4 {

    private int defaultValue = 40;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for ColourController .... Done");
    }
}
class ResetFunctionV4 {

    private List<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> controllers)  {
        this.controllers = controllers;
    }
    void initialize()    {
        for (OnStart onStart :this.controllers)  {
            onStart.checkForDriverUpdate();
        }
    }
}
/*
*       so on
*       There can be n number of controllers
*
* */
public class TvApplicationV4 {
    public static void main(String[] args)  {
        VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
        BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
        ColourControllerV4 colourControllerV4 = new ColourControllerV4();
        List<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> controllersToReset = new ArrayList<>();
        controllersToReset.addAll(controllerV4s);
        ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV4.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV4.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV4.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV4.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV4.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV4.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV4.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Agora, todo o problema enfrentado por você foi abordado e você percebeu que, com o uso de Herança e Polimorfismo, era possível

  1. Mantenha várias partes do aplicativo fracamente acopladas. (Os componentes de recurso Redefinir ou Atualizar driver não precisam ser informados das classes reais do controlador (Volume, Brilho e Cor), qualquer classe que implemente o OnReset ou OnStart será aceitável para Redefinir ou Atualizar driver componentes respectivamente).
  2. O aprimoramento do aplicativo fica mais fácil (a nova adição do controlador não afeta o componente de recurso de redefinição ou atualização de driver, e agora é muito fácil adicionar novos)
  3. Mantenha a camada de abstração (agora o recurso Redefinir pode ver apenas o método setDefault dos controladores e o Redefinir pode ver apenas o método checkForDriverUpdate dos controladores)

Espero que isto ajude :-)

Desenvolvedor
fonte
3

O termo sobrecarga refere-se a várias versões de algo com o mesmo nome, geralmente métodos com diferentes listas de parâmetros

public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }

Portanto, essas funções podem fazer a mesma coisa, mas você tem a opção de chamá-lo com um ID ou um nome. Não tem nada a ver com herança, classes abstratas etc.

Substituição geralmente se refere ao polimorfismo, como você descreveu na sua pergunta

Clyde
fonte
2

sobrecarga é quando você define 2 métodos com o mesmo nome, mas com parâmetros diferentes

overriding é onde você altera o comportamento da classe base por meio de uma função com o mesmo nome em uma subclasse.

Portanto, o polimorfismo está relacionado à substituição, mas não à sobrecarga.

No entanto, se alguém me desse uma resposta simples de "substituição" da pergunta "O que é polimorfismo?" Eu pediria mais explicações.

Matt
fonte
2

substituir é mais como ocultar um método herdado declarando um método com o mesmo nome e assinatura que o método de nível superior (super método), isso adiciona um comportamento polimórfico à classe. em outras palavras, a decisão de escolher qual método de nível a ser chamado será tomada no tempo de execução e não no tempo de compilação. isso leva ao conceito de interface e implementação.

Genjuro
fonte
2

o que é polimorfismo?

Do tutorial em java

A definição de polimorfismo no dicionário refere-se a um princípio em biologia no qual um organismo ou espécie pode ter muitas formas ou estágios diferentes. Esse princípio também pode ser aplicado a programação orientada a objetos e linguagens como a linguagem Java. As subclasses de uma classe podem definir seus próprios comportamentos exclusivos e ainda compartilhar algumas das mesmas funcionalidades da classe pai.

Ao considerar os exemplos e a definição, a substituição deve ser aceita como resposta.

Em relação à sua segunda consulta:

Se você tinha uma classe base abstrata que definiu um método sem implementação e definiu esse método na subclasse, isso ainda está substituindo?

Deve ser chamado de substituição.

Dê uma olhada neste exemplo para entender os diferentes tipos de substituição.

  1. A classe base não fornece implementação e a subclasse precisa substituir o método completo - (resumo)
  2. A classe base fornece implementação padrão e a subclasse pode alterar o comportamento
  3. A subclasse adiciona extensão à implementação da classe base chamando super.methodName() como primeira instrução
  4. A classe base define a estrutura do algoritmo (método Template) e a subclasse substituirá uma parte do algoritmo

fragmento de código:

import java.util.HashMap;

abstract class Game implements Runnable{

    protected boolean runGame = true;
    protected Player player1 = null;
    protected Player player2 = null;
    protected Player currentPlayer = null;

    public Game(){
        player1 = new Player("Player 1");
        player2 = new Player("Player 2");
        currentPlayer = player1;
        initializeGame();
    }

    /* Type 1: Let subclass define own implementation. Base class defines abstract method to force
        sub-classes to define implementation    
    */

    protected abstract void initializeGame();

    /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
    protected void logTimeBetweenMoves(Player player){
        System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
    }

    /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
        super.methodName() in first line of the child class method and specific implementation later */
    protected void logGameStatistics(){
        System.out.println("Base class: logGameStatistics:");
    }
    /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
    protected void runGame() throws Exception{
        System.out.println("Base class: Defining the flow for Game:");  
        while ( runGame) {
            /*
            1. Set current player
            2. Get Player Move
            */
            validatePlayerMove(currentPlayer);  
            logTimeBetweenMoves(currentPlayer);
            Thread.sleep(500);
            setNextPlayer();
        }
        logGameStatistics();
    }
    /* sub-part of the template method, which define child class behaviour */
    protected abstract void validatePlayerMove(Player p);

    protected void setRunGame(boolean status){
        this.runGame = status;
    }
    public void setCurrentPlayer(Player p){
        this.currentPlayer = p;
    }
    public void setNextPlayer(){
        if ( currentPlayer == player1) {
            currentPlayer = player2;
        }else{
            currentPlayer = player1;
        }
    }
    public void run(){
        try{
            runGame();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

class Player{
    String name;
    Player(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

/* Concrete Game implementation  */
class Chess extends Game{
    public Chess(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized Chess game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate Chess move:"+p.getName());
    }
    protected void logGameStatistics(){
        super.logGameStatistics();
        System.out.println("Child class: Add Chess specific logGameStatistics:");
    }
}
class TicTacToe extends Game{
    public TicTacToe(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized TicTacToe game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate TicTacToe move:"+p.getName());
    }
}

public class Polymorphism{
    public static void main(String args[]){
        try{

            Game game = new Chess();
            Thread t1 = new Thread(game);
            t1.start();
            Thread.sleep(1000);
            game.setRunGame(false);
            Thread.sleep(1000);

            game = new TicTacToe();
            Thread t2 = new Thread(game);
            t2.start();
            Thread.sleep(1000);
            game.setRunGame(false);

        }catch(Exception err){
            err.printStackTrace();
        }       
    }
}

resultado:

Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Ravindra babu
fonte
2

Acho que vocês estão misturando conceitos. Polimorfismo é a capacidade de um objeto se comportar de maneira diferente em tempo de execução. Para conseguir isso, você precisa de dois requisitos:

  1. Ligação tardia
  2. Herança.

Dito isto, sobrecarregar significa algo diferente de substituir, dependendo do idioma que você está usando. Por exemplo, em Java, não existe substituição, mas sobrecarga . Métodos sobrecarregados com assinatura diferente de sua classe base estão disponíveis na subclasse. Caso contrário, eles seriam substituídos (por favor, veja que agora quero dizer que não há como chamar seu método de classe base de fora do objeto).

No entanto, em C ++ não é assim. Qualquer método sobrecarregado , independentemente de a assinatura ser a mesma ou não (quantidade diferente, tipo diferente) também é substituído . Hoje, o método da classe base não está mais disponível na subclasse ao ser chamado de fora do objeto da subclasse, obviamente.

Portanto, a resposta é quando se fala em Java, use sobrecarga . Em qualquer outro idioma pode ser diferente, como acontece em c ++

user1154840
fonte
1

Polimorfismo é mais provável na medida em que significa ... para SUBSTITUIR em java

Trata-se de um comportamento diferente do mesmo objeto em diferentes situações (na maneira de programar ... você pode chamar ARGUMENTOS diferentes)

Acho que o exemplo abaixo o ajudará a entender ... Embora não seja um código java PURO ...

     public void See(Friend)
     {
        System.out.println("Talk");
     }

Mas se mudarmos o ARGUMENTO ... o COMPORTAMENTO será alterado ...

     public void See(Enemy)
     {
        System.out.println("Run");
     }

A Pessoa (aqui o "Objeto") é a mesma ...

Rajan
fonte
1

Polimorfismo é uma implementação múltipla de um objeto ou você pode dizer várias formas de um objeto. digamos que você tenha classe Animalscomo a classe base abstrata e ele tenha um método chamado movement()que define a maneira como o animal se move. Agora, na realidade, temos diferentes tipos de animais e eles se movem de maneira diferente, alguns com 2 pernas, outros com 4 e outros sem pernas, etc. Para definir diferentes movement()animais de cada terra, precisamos aplicar o polimorfismo. No entanto, você precisa definir mais classes, ou seja, classe Dogs Cats Fishetc. Em seguida, você precisa estender essas classes da classe base Animalse substituir seu método movement()por uma nova funcionalidade de movimento com base em cada animal que você possui. Você também pode usarInterfacespara conseguir isso. A palavra-chave aqui é primordial, a sobrecarga é diferente e não é considerada polimorfismo. com sobrecarga, você pode definir vários métodos "com o mesmo nome", mas com parâmetros diferentes no mesmo objeto ou classe.

SolidSnake
fonte
0

Polimorfismo refere-se à capacidade de uma linguagem ter diferentes objetos tratados de maneira uniforme usando uma única interface; como tal, está relacionado à substituição, portanto a interface (ou a classe base) é polimórfica, o implementador é o objeto que substitui (duas faces da mesma medalha)

de qualquer maneira, a diferença entre os dois termos é melhor explicada usando outras linguagens, como c ++: um objeto polimórfico em c ++ se comporta como o equivalente em java se a função base for virtual, mas se o método não for virtual, o salto de código será resolvido estaticamente , e o tipo verdadeiro não verificado no tempo de execução, portanto, o polimorfismo inclui a capacidade de um objeto se comportar de maneira diferente, dependendo da interface usada para acessá-lo; deixe-me fazer um exemplo no pseudocódigo:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(supondo que makeRumor NÃO seja virtual)

java não oferece realmente esse nível de polimorfismo (também chamado de corte de objetos).

animal a = novo cachorro (); cachorro b = cachorro novo ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

em ambos os casos, apenas imprimirá woff .. uma vez que aeb está se referindo à classe dog

Lorenzo Boccaccia
fonte
animal a = novo cachorro (); a foi construído como um cachorro e imprimirá "woff". Se você quer que ele para imprimir baque, então você precisa upcast ele ((animal) a) .makeRumor ().
Chris Cudmore
Isso é referência positiva, mas o objeto ainda é um cachorro. Se você deseja que ele seja um animal, você deve explicitamente aumentar o objeto.
31830 Chris Cudmore
Descobri isso. A pergunta foi etiquetada como Java. Você respondeu C ++. Você pode estar correto em C ++. Definitivamente, estou correto em Java.
22630 Chris Cudmore
deve acontecer toda vez que um construtor de cópias está envolvido aqui é uma referência fredosaurus.com/notes-cpp/oop-condestructors/… caso três correspondências; ignore o novo operador que existe apenas para desambiguar a criação.
Lorenzo Boccaccia
0
import java.io.IOException;

class Super {

    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName() + " - I'm parent");
        return null;
    }

}

class SubOne extends Super {

    @Override
    protected Super getClassName(Super s)  {
        System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
        return null;
    }

}

class SubTwo extends Super {

    @Override
    protected Super getClassName(Super s) throws NullPointerException {
        System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
        return null;
    }

}

class SubThree extends Super {

    @Override
    protected SubThree getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
        return null;
    }

}

class SubFour extends Super {

    @Override
    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
        return null;
    }

}

class SubFive extends Super {

    @Override
    public Super getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
        return null;
    }

}

class SubSix extends Super {

    public Super getClassName(Super s, String ol) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
        return null;
    }

}

class SubSeven extends Super {

    public Super getClassName(SubSeven s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
        return null;
    }

}

public class Test{

    public static void main(String[] args) throws Exception {

        System.out.println("Overriding\n");

        Super s1 = new SubOne(); s1.getClassName(null);

        Super s2 = new SubTwo(); s2.getClassName(null);

        Super s3 = new SubThree(); s3.getClassName(null);

        Super s4 = new SubFour(); s4.getClassName(null);

        Super s5 = new SubFive(); s5.getClassName(null);

        System.out.println("Overloading\n");

        SubSix s6 = new SubSix(); s6.getClassName(null, null);

        s6 = new SubSix(); s6.getClassName(null);

        SubSeven s7 = new SubSeven(); s7.getClassName(s7);

        s7 = new SubSeven(); s7.getClassName(new Super());

    }
}
bharanitharan
fonte