Develop code that makes use of polymorphism; develop code that overrides methods; differentiate between the type of a reference and the type of an object

Desenvolver código que faz uso de polimorfismo:

O polimorfismo em Java permite que objetos de diferentes classes sejam tratados como objetos da mesma classe, permitindo a flexibilidade no design de código. Um exemplo de polimorfismo usando herança e sobrescrita de métodos:

class Animal {
    void fazerSom() {
        System.out.println("Algum som de animal");
    }
}

class Cachorro extends Animal {
    @Override
    void fazerSom() {
        System.out.println("Latido de cachorro");
    }
}

class Gato extends Animal {
    @Override
    void fazerSom() {
        System.out.println("Miado de gato");
    }
}

public class ExemploPolimorfismo {
    public static void main(String[] args) {
        Animal animal1 = new Cachorro();
        Animal animal2 = new Gato();

        animal1.fazerSom();  // Resultado: Latido de cachorro
        animal2.fazerSom();  // Resultado: Miado de gato
    }
}

Neste exemplo, Cachorro e Gato são subclasses de Animal. Criamos instâncias de Cachorro e Gato, mas as referências são do tipo Animal. O método fazerSom é sobrescrito nas subclasses, e ao chamar esse método através das referências do tipo Animal, o método apropriado da subclasse é executado.

Diferenciar entre o tipo de uma referência e o tipo de um objeto:

public class ExemploTipoReferenciaObjeto {
    public static void main(String[] args) {
        Animal animal1 = new Cachorro();
        Animal animal2 = new Gato();

        // Tipo de referência
        System.out.println("Tipo de referência de animal1: " + animal1.getClass().getSimpleName());
        System.out.println("Tipo de referência de animal2: " + animal2.getClass().getSimpleName());

        // Tipo de objeto
        System.out.println("Tipo de objeto de animal1: " + determinarTipoObjeto(animal1));
        System.out.println("Tipo de objeto de animal2: " + determinarTipoObjeto(animal2));
    }

    static String determinarTipoObjeto(Object objeto) {
        return objeto.getClass().getSimpleName();
    }
}

Neste exemplo, a classe ExemploTipoReferenciaObjeto diferencia entre o tipo de referência e o tipo de objeto. O método determinarTipoObjeto recebe um objeto e retorna o tipo do objeto como uma string. Isso ilustra como a referência pode ter um tipo mais genérico (Animal), enquanto o objeto real tem um tipo mais específico (Cachorro ou Gato).