questo è spiegato in questo blog: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ050
rilevanti citazione:
Come può accadere questo? Passiamo un argomento di tipo String al metodo sovraccarico e tuttavia viene chiamata la versione per il tipo Object. Il motivo è che il compilatore crea solo una rappresentazione di codice byte per tipo o metodo generico e mappa tutte le istanze del tipo o metodo generico a quella rappresentazione.
Nell'esempio il metodo generico viene traslata nella seguente rappresentazione:
(edit: ho cambiato il metodo per abbinare questa domanda)
public String doYapStuff(Object x) {
return "sad";
}
Considerando questa traduzione, dovrebbe essere ovvio perché viene invocata la versione Object del metodo overload. È del tutto irrilevante quale tipo di oggetto viene passato al metodo generico e quindi passato al metodo sovraccarico. Osserveremo sempre una chiamata della versione Object del metodo overload.
Più in generale: la risoluzione del sovraccarico si verifica in fase di compilazione, ovvero il compilatore decide quale versione in sovraccarico deve essere richiamata. Il compilatore lo fa quando il metodo generico viene tradotto nella sua rappresentazione di byte code univoca. Durante quel tipo di traduzione viene eseguita la cancellazione, il che significa che i parametri di tipo vengono sostituiti dal loro limite più a sinistra o da Oggetto se non è stato specificato alcun limite. Di conseguenza, il limite più a sinistra o Object determina quale versione di un metodo sovraccarico viene richiamata. Quale tipo di oggetto viene passato al metodo in fase di esecuzione è del tutto irrilevante per la risoluzione del sovraccarico.
Si può vedere questo se si guarda al bytecode compilato:
4 getfield Woof$Arf.yap : java.lang.Object [16]
7 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [32]
10 aload_0 [this]
11 aload_0 [this]
12 getfield Woof$Arf.yap : java.lang.Object [16]
15 invokevirtual Woof$Arf.doYapStuff(java.lang.Object) : java.lang.String [37]
18 areturn
per ottenere quello che vuoi, probabilmente è necessario utilizzare il modello strategia.
public interface YapSound{
String doYapSound();
}
public class HappySound implements YapSound{
@Override
public String doYapSound() {
return "happy";
}
}
public class SadSound implements YapSound{
@Override
public String doYapSound() {
return "sad";
}
}
public class Arf {
YapSound yap;
public Arf(YapSound yap) {
this.yap = yap;
}
public String woof() {
/*
* Should select which doYapStuff() based on whether T
* happens to be an Integer, or something else.
*/
return yap.doYapSound();
}
}
public static void main(String[] args) {
Arf arf1 = new Arf(new HappySound());
System.out.println(arf1.woof()); // Should print "happy"
Arf arf2 = new Arf(new SadSound());
System.out.println(arf2.woof()); // Should print "sad"
}