Polimorfismo (dúvida)

Bom, procurei já aqui no fórum e tudo mais, mas preciso tirar essa dúvida.

Antes dando créditos ao Mantu, foi de um tópico dele de onde tirei algumas dúvidas e me surgiram outras.

eu tendo a classe Funcionário:

public class Funcionario{
     //variaveis....
     //métodos....        

}

e tenho outras 2 classes Comissionado e Horista:

public class Comissionado extends Funcionario{
       //além das variáveis do pai(sem necessidade de declarar aqui é obvio), 
       //terá mais as especificas dele. (eu penso assim, se eu tiver errado me corrijam)
       //e os métodos especificos, ou os que irão sobre-escrever os da classe pai
}

public class Horista extends Funcionario {
// Aqui vale o comentário de cima também.
}

AGORA é a DÚVIDA CRUEL!:

eu poderia fazer:

public class Main {

    public static void main(String[] args) {
          Comissionado comissionado = new Comissionado();
          //com isso eu poderia acessar metodos, get/set da classe pai (por ter o extends) até aqui beleza...

          // Por que raios eu utilizaria isso:

          Funcionario func = new Comissionado(); 
          Comissionado comi = (Comissionado) func; 


          //Pelo o que eu entendi, e fui pra casa pensando agora no almoço foi...
          //que na linha 09 tá dizendo o func é do tipo funcionario que tá recebendo um objeto Comissionado.
          //entaum se... chamar um metodo do func. ex:

          func.calculaSalario();

          //a verificação vai acontecer como o func é do tipo funcionário mas recebeu um Comissionado
          //o método que irá executar *se houver* vai ser primeiro do Comissionado, senão executará o método do pai
          //(Me corrijam e digam onde estou falando besteira)

          //Mas agora é a questão... quando feito:
          //a linha 09, na minha cabeça fico o seguinte, "func recebeu tudo que tem do comissionado e tem tudo que funcionario"
          //MAASSSS..... 
          //quando tentei executar
          func.setValorComissao(); // é um método do comissionado quem disse que ele achou?! 
          //achou só os métodos do Funcionário *Diacho*!
 
          // COMO DEVO ANALISAR NA LINHA 09 ? 
          //"A classe pai é inferior a filho, e quando feito a linha 09, será analisado tudo que é igual, 
          //manterá o que é diferente descarta?
          //se tiver método iguais(mesmo nome) será mantido e quando executado será do Comissionario (overriding)
          //mas e os métodos que são do Comissionado?!"

          //as linhas 09 e 10 não é a mesma coisa que a linha 04? não tem a mesma função?!
          //ou melhor quando eu utilizaria as linhas 09 e 10?!
                      

    }
}

Peço desculpas por estar meio grande, mas tentei deixar o mais claro possível a minha dúvida.
Obrigado desde já

Estou supondo que “setValorComissao” é um método de Comissionado.

De fato, você poderia chamar setValorComissao sobre o objeto referenciado pela variável func, mas o problema é que

func.setValorComissao()

não compila, porque o compilador não sabe que, naquela linha em particular, func referencia um objeto do tipo Comissionado.

Para isso compilar, é necessário indicar explicitamente que func referencia como um objeto do tipo Comissionado, e se por acaso não for um objeto desse tipo, deve lançar uma ClassCastException. Isso é feito através de:

((Comissionado) func).setValorComissao()

ou então

comi.setValorComissao()

Uma coisa que dá muita dor de cabeça para muita gente é que referências (ou seja, variáveis) e objetos são coisas distintas; uma delas é um endereço (“Rua dos Bobos, 0”) e a outra é a casa (a casa que fica na Rua dos Bobos, 0).

então o compilador olha func é do tipo Funcionário nem olha se recebeu Comissionado.

só ira olhar quando executado um método por exemplo que tenha nas 2 classes:

  func.calcularSalario(); 

o compilador verificará se tem no Comissionado, se tiver ele executa. se não tiver vai pro do Funcionário.

Certo ou errado?

Mais ou menos; na verdade, essa verificação é feita em tempo de execução (pela JVM), não de compilação.
Mas é mais ou menos isso mesmo que você falou.

A JVM é bastante esperta e se ela conseguir provar, durante a execução do programa, que a tal variável sempre vai conter um objeto do tipo Comissionado, ela irá chamar diretamente o método da classe Comissionado, sem efetuar novamente a tal verificação. Por isso, não há “perda de tempo” para fazer a tal verificação. Isso faz com que alguns programas Java comecem mais devagar e depois de algum tempo (“aquecimento”) eles comecem a ficar mais rápidos.