Ok ma .. vediamo alcune questioni:
- meno importante, hai usato X come type variable. Nulla di male o errato ma convenzionalmente si usa T (o E nel caso delle collezioni). O altre lettere in casi più particolari (es. K, V per le map). La X è usata molto raramente (c'è un caso d'uso, in Java 8 la nuova classe Optional ha il orElseThrow che ha una type variable <X extends Throwable> dedicata appunto alla exception).
- Il ? extends X va bene, così è semplicemente più "ampio". Se passi un Highscore.class, l'inferenza dei tipi permette ad esempio di assegnare ad un List<Object> (perché logicamente qualunque Highscore ci sta in una lista di Object!).
Senza il extends, se passi Highscore.class, allora devi assegnare ad un List<Highscore> . Tutto qui.
- La gestione delle eccezioni è un po' fumosa. Sarebbe meglio far uscire l'eccezione fuori dal metodo. E se vogliamo fare i fini, sarebbe anche buono creare una eccezione di più alto livello che incapsula l'eccezione di più basso livello.
- il fatto di creare il file ... no, non è buono. Non è readElement che dovrebbe occuparsene.
No, nel P.S. di prima non dicevo questo! Intendevo che non so (sapevo) come avevi fatto il design della classe e che ci possono essere varie forme possibili.
Allora qui è meglio chiarire, perché stai facendo confusione.
Se dichiari la type variable al livello della classe ReaderWriter (che quindi diventa "generica"), va bene, è una scelta possibile. Ma così vai a fissare anche il tipo di ritorno di readElement che è List<X>. Se nell'uso concreto fai un ReaderWriter<Object>, allora vai a fissare che readElement ritorna un List<Object>. Certo ... con lo STESSO oggetto ReaderWriter<Object> puoi invocare readElement con ClasseABC.class e poi un'altra invocazione con ClasseXYZ.class. Ma in uscita hai un List<Object> e questo NON è poi molto utile.
Se fai un ReaderWriter<Highscore> allora è abbastanza chiaro che quella istanza la dovrai usare solo per leggere oggetti Highscore (quindi List<Highscore>). Per trattare un'altra classe, dovrai creare un'altra istanza, parametrizzata diversamente.
Se non è questo che vuoi ... non è quello il design giusto!
Poi c'è anche la questione del filename. Se non lo passi al costruttore, allora le istanze di ReaderWriter a cosa servono? O per dire meglio: due istanze di ReaderWriter in cosa si distinguerebbero e per cosa? Appunto .... Poi magari al momento potrebbero non avere alcun "stato" ma magari in futuro potrebbero avere qualche configurazione o dato specifico per quella istanza.
Tecnicamente sì, puoi rendere readElement un metodo statico (di "utilità") che è "generico" e riceve il filename.