Eu vou me limitar à explicação da função soma2(), que é um erro que faz mas sentido pra mim:
public <T extends Integer> T soma2() {
return new Integer(35);
}
Dá erro porque, quando digo , estou querendo dizer: “meu retorno é um Integer ou qualquer subclasse de Integer”. É claro que isso é só teoria, na prática, por Integer ser final, não existe uma sublasse pra ela. Mas, se fizéssemos assim:
public <T extends NumberFormat> T soma2() {
// TODO
}
Isso seria válido:
DecimalFormat df = soma2();
ChoiceFormat cf = soma2();
E não há casting porque tipo genérico está explicitamente dizendo que o objeto pode ser convertido para qualquer subclasse de NumberFormat.
Por ser possível atribuir a uma subclasse, isso não pode compilar:
public <T extends NumberFormat> T soma2() {
return NumberFormat.getInstance(); // não compila!
}
Porque estou, no final das contas atribuindo uma superclasse a uma possível subclasse.
Fazendo isso, compila:
public <T extends NumberFormat> T soma2() {
return (T) NumberFormat.getInstance(); // não compila!
}
Mas há um risco de ClassCastException durante a execução.
Agora, com relação a primeria função do exemplo do cara, não entendo porque compila. Pra mim, deveria dar erro também.