tengo este metodo:
public <T extends CacheResult> T get(Object key, CacheDefinition cacheDefinition) { return load(key, cacheDefinition.name(), cacheDefinition.getTypeReference()); }Ahora mi IDE se queja (como se esperaba y es correcto) sobre esta línea, porque se supone que el tipo de retorno es CacheResult
User user = spxCacheManager.get(username, CacheDefinition.USERS_BY_USERNAME);Lo que actualmente no entiendo es que el IDE (IntelliJ) no se queja de esto:
List<User> usersFromCache = spxCacheManager.get(username, CacheDefinition.USERS_BY_USERNAME);Lo que en realidad está mal. ¿Que me estoy perdiendo aqui?
Esto funciona porque T se infiere como un tipo de intersección: List<User> & CacheResult & Object . Después de todo, ¿por qué una clase no puede implementar List<User> e implementar/extender CacheResult ? ¡Tal tipo es ciertamente posible!
Puede ver que esto suceda escribiendo un programa de juguete y usando la --debug=verboseResolution=all :
import java.util.List; public class Main { public static void main(String[] args) { List<User> u = new Main().get(); } public <T extends CacheResult> T get() { return null; } } interface CacheResult {} class User implements CacheResult {} javac con verboseResolution=all generaría:
instantiated signature: ()INT#1 target-type: List<User> where T is a type-variable: T extends CacheResult declared in method <T>get() where INT#1 is an intersection type: INT#1 extends Object,List<User>,CacheResult También puede seguir el proceso de cómo Java escribe la inferencia . Eventualmente (en algún lugar de la "resolución"), llegará a un punto en el que necesita encontrar el límite inferior más grande ("glb") de Object , List<User> y CacheResult , y ese tipo es exactamente su tipo de intersección, como se define aquí
Por otro lado, su código no se compilará si CacheResult es una clase y el tipo al que está asignando el resultado del método es una clase no relacionada, ya que ninguna clase puede heredar de dos clases no relacionadas.