Vamos imaginar que a classe Animal tem o método dormir e a classe cachorro tem o método latir. Animal é um animal, mas não é um Cachorro, por isso esse objeto só consegue usar o método dormir; Cachorro é um cachorro e também é um Animal, por isso ele consegue usar o método dormir e latir.
Animal animal = new Cachorro() -
Cria uma instância de um objeto do tipo Cachorro e guarda numa variável do tipo animal. Como a instância foi guardada num objeto Animal, mesmo ela sendo do tipo Cachorro, fica limitada a usar o método dormir sem poder usar latir.
if (animal instanceof Cachorro) -
Verificar se o objeto na variável animal é uma instância de um objeto Cachorro. Caso seja verdadeiro, entra no bloco do if.
Cachorro cachorro = (Cachorro) animal -
utiliza um recurso chamado cast para para converter aquela variável animal para o tipo Cachorro. A sintaxe (Cachorro) animal indica ao compilador que você está convertendo explicitamente a referência animal para o tipo Cachorro. Isso significa que você está informando ao compilador que tem certeza de que animal é um Cachorro. Agora que está convertido, podemos usar o método dormir e latir usando a variável cachorro. Se a verificação desse false, cairia no bloco do else, imprimindo a mensage "O objeto não é um Cachorro" no console.
Cachorro cachorro = (Cachorro) animal
Esse código só foi possível porque Cachorro e Animal possuem uma relação de herança, ela foi estabelecida quando Cachorro extendeu de Animal.
Aqui vão alguns exemplos:
// Esse código seria impossível, o objeto Animal não é um cachorro.
Cachorro cachorro = new Animal();
// O contrário é possível pois Cachorro é um objeto Cachorro e um objeto Animal, mas desse jeito não será possível usar o método latir, porque a instância está guardado num tipo Animal
Animal animal = new Cachorro();
// Esse código não seria possível, pois Animal e Planta não têm relação de herança (não faria sentido criar herança entre eles). Um animal não é uma Planta e uma Planta não é um Animal
Animal animal = new Planta();
// As três linhas a seguir seriam possíveis, pois os objetos Planta, Animal e Cachorro com certeza possuem uma relação de herança com objeto SerVivo. Um ser vivo não é uma Planta, nem Animal e nem Cachorro, mas uma Planta é um SerVivo e etc
SerVivo criatura1 = new Planta();
SerVivo criatura2 = new Animal();
SerVivo criatura3 = new Cachorro();
// Novamente um código impossível. Um SerVivo não é uma Planta, mas o contrário é possível pois uma planta é uma Planta e também é um SerVivo
Planta criaturinha = new SerVivo();
Espero ter ajudado. Se foi útil pra você para você, marca como sulução. Bons estudos!