Sto studiando i tipi generici e mi sono bloccato nella comprensione di un esempio.
Il manuale cita questo esempio:
codice:
interface Cibo
{
     String getColore();
}
codice:
interface Animale
{
    void mangia(Cibo cibo) throws CiboException
}
codice:
public class Erba implements Cibo
{
    public String getColore()
    {
          return "verde";
    }
}
codice:
public class Carnivoro implements Animale
{
    public void mangia(Cibo cibo) throws CiboException
    {
         if(!(cibo instanceof Erbivoro)
         {
               throw new CiboException("Un carnivoro deve mangiare " + "erbivori");
         }      
    }
}
codice:
public class Erbivoro implements Cibo, Animale
{
    public void mangia(Cibo cibo) throws CiboException
    {
         if(!(cibo instanceof Erba)
         {
               throw new CiboException("Un erbivoro deve mangiare " + "erba");
         }
    }
    
    public String getColore()
    {
          ...
    }
}
codice:
public class CiboException extends Exception
{
    public CiboException(String msg)
    {
          super(msg);
    }
}
codice:
public class TestAnimali
{
    public static void main(String args[])
    { 
         try
         {
               Animale tigre = new Carnivoro();
               Cibo erba = new Erba();
               tigre.mangia(erba);
         }
         catch(CiboException exc)
         {
               exc.printStackTrace();
         }
    }
}


Questa soluzione è valida però il manuale, per evitare la gestione delle eccezioni, ne propone un'altra utilizzando i tipi parametro:
codice:
interface Cibo
{
     String getColore();
}
codice:
interface Animale<C extends Cibo>
{
    void mangia(C cibo)
}
codice:
public class Erba implements Cibo
{
    public String getColore()
    {
          return "verde";
    }
}
codice:
public class Carnivoro implements Animale<Erbivoro>
{
    public void mangia(Erbivoro erbivoro)
    {
         // un carnivoro potrebbe mangiare erbivori
    }
}
codice:
public class Erbivoro<E extends Erba> implements Cibo, Animale<E>
{
    public void mangia(E erba)
    {
          // un erbivoro mangia erba
    }
    
    public String getColore()
    {
          ...
    }
}
codice:
public class TestAnimali
{
    public static void main(String args[])
    { 
         Animale<Erbivoro> tigre = new Carnivoro<Erbivoro>();
         Erbivoro<Erba> erbivoro = new Erba<Erba>();
         tigre.mangia(erbivoro);
    } 
}

Il problema è che non ho capito nell'ultima soluzione come ha utilizzato i tipi parametro, mi sfuggono proprio i vari passaggi nel codice.
Potete aiutarmi nella comprensione?