Tengo una clase llamada CacheRequestWrapper que tiene un campo con un tipo genérico. También tiene otro campo de tipo Optional<Long> . Cuando la clase se haga genérica, el valor de este campo opcional ya no será de tipo Long . En su lugar, será de tipo Object .
En otras palabras, cuando hago que la clase sea genérica, el tipo genérico de Optional se borra y no entiendo por qué. Solo el campo cacheReturnValue debe ser de tipo T , pero parece que el tipo T también está asignado a Optional . Permítanme explicar por qué este parece ser el caso con el siguiente ejemplo:
public class CacheRequestWrapper<T> extends CacheWrapper { private T cacheReturnValue; private Optional<Long> requestingUserId; public Optional<Long> getRequestingUserId() { return requestingUserId; } public void setRequestingUserId(Optional<Long>requestingUserId) { this.requestingUserId = requestingUserId; } //other Getters, setters } class Service{ //1. private void myRawTypedMethod(CacheRequestWrapper cacheRequestWrapper) { Long viewerId = cacheRequestWrapper.getRequestingUserId().get(); //This gives the compile error 'required type: Long, provided type Object' } //2. private <T> void myGenericTypedMethod(CacheRequestWrapper<T> cacheRequestWrapper) { Long viewerId = cacheRequestWrapper.getRequestingUserId().get(); //No compile error here. } } En el método 1. Obtengo un error de compilación cuando asigno el valor opcional a viewerId . En el método genérico 2. , el error de compilación no está presente. No está claro por qué, pero lo que creo que está sucediendo es que el tipo Long de Optional se reemplaza por T por alguna razón. Esto genera un problema porque durante el tiempo de ejecución T no siempre es del mismo tipo que Long .
Entonces, ¿por qué el tipo genérico del campo Optional está anulado por el tipo genérico T ?
Este comportamiento se especifica en la Sección 4.8 de la Especificación del lenguaje Java . Un tipo genérico sin los parámetros de tipo se denomina tipo sin formato, y en un tipo sin formato se borran casi todos los genéricos.
Los tipos sin procesar solo están destinados a interactuar con el código Java heredado (versión 1.4 o inferior) que no tiene genéricos, y para facilitar esta interacción, todos los genéricos deben borrarse porque el código heredado podría querer hacer cosas que los genéricos prohibirían.
Por ejemplo, algo como
String id = (String)wrapper.getRequestingUserId().orElseThrow(); no compilaría si los genéricos no se borraran. Lo admito, este es un ejemplo extraño porque Optional se agregó al lenguaje Java más tarde que los genéricos y no aparecería en el código heredado, pero Java no hace una excepción.
Dado que el código Java anterior a 1.4 se está volviendo cada vez más raro, el código nuevo rara vez debería usar tipos sin formato.