Clase1 referencia = new Clase4()
Ahí se está instanciando un objeto de Clase4.
Sin embargo, se está referenciando como un objeto de Clase1.
Por lo tanto, de forma directa, solo podrán invocarse los métodos de Clase1.
Sin embargo, al invocar el método multiplicar(), como está sobreescrito en Clase2, será este método el que se ejecute, a pesar de que la referencia está como Clase1.
No podrá invocarse el método potenciacion() de forma directa. Sería necesario hacer un casting a Clase4, aún cuando lo que hemos instanciado es precisamente un Clase4.
Este es un buen ejercicio para distinguir entre los conceptos "instanciar" y "referenciar".
Puedes ponerlo a prueba mediante el código que dejo abajo.
Incluso puedes probarlo también y hacer más pruebas, en este editor online:
https://www.online-ide.com/8c6koBTxQvpublic class Main
{
public static void main(String[] args) {
Clase1 referencia = new Clase4(); //Instanciamos un Clase4, pero lo referenciamos como Clase1
referencia.multiplicar(); //Multiplicar de Clase2, aunque la referencia es Clase1, pero Clase2 lo ha sobreescrito
((Clase4) referencia).potenciacion(); //Para llamar a potenciacion() se requiere casting, a pesar de que es una instancia de Clase4
}
static class Clase1 {
public void sumar() {
System.out.println("Sumar de clase 1");
}
public void restar() {
System.out.println("Restar de clase 1");
}
public void multiplicar() {
System.out.println("Multiplicar de clase 1");
}
}
static class Clase2 extends Clase1 {
public void multiplicar() {
System.out.println("Multiplicar de clase 2");
}
}
static class Clase3 extends Clase1 {
public void sumar() {
System.out.println("Sumar de clase 3");
}
}
static class Clase4 extends Clase2 {
public void potenciacion() {
System.out.println("Potenciacion de clase 4");
}
}
}