Visualizzazione dei risultati da 1 a 7 su 7

Discussione: Generici e array

  1. #1
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    613

    Generici e array

    Salve.
    Fino a questo momento conoscevo i Generics di Java ed utilizzavo classi che si basavano su di essi, oggi ho cominciato ad utilizzarli io stesso per le mie classi e c'è una parte del loro funzionamento che non mi è chiara.
    So che i tutorial ufficiali di Java parlano di questo ma anche da quelli non sono ancora riuscito a capire bene.
    Il problema riguarda array generici.

    Se io ho una classe Classe<T>, con un campo privato ArrayList<T> (ma anche più generalmente un qualsiasi List<T>), non riesco a scrivere un metodo funzionante che mi restituisca un semplice array di elementi di tipo T.

    Innanzitutto, è possibile? A quanto leggo online mi pare di si.
    E' corretto concettualmente? Nel senso, non vedo problemi di sicurezza in quanto non c'è input quindi, se tutto il resto è implementato correttamente, non dovrebbero sorgere problemi di casting, giusto?
    Come faccio? Ho trovato svariati modi online ma francamente non ci ho capito molto, complice qualche carenza in inglese

    Insomma:

    codice:
    class Class<T> {
    
    ArrayList<T> = new ArrayList<>();
    
    public T[] getElements() {
    
    // qui che ci metto? il metodo è dichiarato correttamente?
    
    }
    
    }
    Grazie.

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Generici e array

    Originariamente inviato da Kaamos
    Se io ho una classe Classe<T>, con un campo privato ArrayList<T> (ma anche più generalmente un qualsiasi List<T>), non riesco a scrivere un metodo funzionante che mi restituisca un semplice array di elementi di tipo T.
    Sì, è tecnicamente possibile ma c'è una questione concettuale e tecnica di fondo molto importante.

    I Generics sono implementati per "erasure". Vuol dire che quando ad esempio istanzi un TuaClasse<String>, all'interno di questo oggetto non c'è scritto da alcuna parte che "è di String". Per erasure quel T diventa Object.

    Cosa vuol dire? Vuol dire che tu tecnicamente, se volessi, potresti offrire un metodo del tipo:

    public Object[] getElements()

    Al suo interno istanzi un Object[], lo popoli e lo restituisci. Ma sarebbe limitato. Perché il "client" che lo usa deve per forza usarlo come Object[]. Non può fare un cast a String[]. Se un array è un Object[] ... chiaramente non è un String[], intendo dire proprio come tipo dell'array in sé.

    Ma se volessi fare in modo che se T è String si vuole restituire un array che sia davvero un String[] ? Si può fare ma ripeto la questione sopra: il tuo oggetto TuaClasse non "sa" che tu l'hai istanziata parametrizzandola con <String>.

    Come si fa allora? Semplice: la soluzione "tipica" è quella di passare al metodo un array di quel tipo! E tramite "reflection" viene dedotto il tipo effettivo dell'array.

    Hai mai visto che in java.util.List ci sono 2 metodi toArray() ?

    Object[] toArray()
    <T> T[] toArray(T[] a)

    Il secondo deve ricevere un array (anche "vuoto", di dimensione 0) affinché si possa avere un array di quel giusto tipo con gli elementi della lista.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    613

    Re: Re: Generici e array

    Originariamente inviato da andbin
    Sì, è tecnicamente possibile ma c'è una questione concettuale e tecnica di fondo molto importante.

    I Generics sono implementati per "erasure". Vuol dire che quando ad esempio istanzi un TuaClasse<String>, all'interno di questo oggetto non c'è scritto da alcuna parte che "è di String". Per erasure quel T diventa Object.

    Cosa vuol dire? Vuol dire che tu tecnicamente, se volessi, potresti offrire un metodo del tipo:

    public Object[] getElements()

    Al suo interno istanzi un Object[], lo popoli e lo restituisci. Ma sarebbe limitato. Perché il "client" che lo usa deve per forza usarlo come Object[]. Non può fare un cast a String[]. Se un array è un Object[] ... chiaramente non è un String[], intendo dire proprio come tipo dell'array in sé.

    Ma se volessi fare in modo che se T è String si vuole restituire un array che sia davvero un String[] ? Si può fare ma ripeto la questione sopra: il tuo oggetto TuaClasse non "sa" che tu l'hai istanziata parametrizzandola con <String>.

    Come si fa allora? Semplice: la soluzione "tipica" è quella di passare al metodo un array di quel tipo! E tramite "reflection" viene dedotto il tipo effettivo dell'array.

    Hai mai visto che in java.util.List ci sono 2 metodi toArray() ?

    Object[] toArray()
    <T> T[] toArray(T[] a)

    Il secondo deve ricevere un array (anche "vuoto", di dimensione 0) affinché si possa avere un array di quel giusto tipo con gli elementi della lista.
    Capisco, ti ringrazio, effettivamente avevo visto quei due metodi ed infatti non capivo il perché di quel parametro.

    Quindi per il momento non sembra esserci via d'uscita (non che sia importante), a quanto ho capito se Array.newInstance() fosse implementato diversamente si potrebbe fare ma per ora no...

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Re: Re: Generici e array

    Originariamente inviato da Kaamos
    Quindi per il momento non sembra esserci via d'uscita (non che sia importante), a quanto ho capito se Array.newInstance() fosse implementato diversamente si potrebbe fare ma per ora no...
    In che senso? Scusa ma non ho capito quale è il problema che ti poni.

    Se la TuaClasse<T> ha un List<T> dentro e vuoi fornire all'esterno un array T[] di quella lista allora la cosa più banale e diretta è quella di offrire un metodo (chiamalo come vuoi) per ottenere l'array T[] e al suo interno invocare il toArray del List. Naturalmente il tuo metodo riceve un T[] esattamente come fa toArray. Né più né meno.

    Se devi fare/offrire qualcosa di specifico oppure se non hai un List<T> ma qualcos'altro (e che magari non ha nemmeno un toArray o simile), allora sì, ti tocca vedere un po' più da vicino la "reflection" (ma nemmeno più di tanto).

    Da Java 6 comunque la classe di utility java.util.Arrays ha dei comodi metodi copyOf. Il copyOf tra l'altro (sempre da Java 6) è proprio il metodo usato nel toArray ad esempio di ArrayList.
    Per versioni pre-Java 6, purtroppo c'è da usare direttamente java.lang.reflect.Array ma c'è da usare poi solo 1 metodo oltretutto statico (il newInstance).
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    613
    Si nell'ultimo post non mi son spiegato... intendevo dire che concettualmente la Class<T> potrebbe sapere T, gli basterebbe prendere il tipo di uno degli elementi del suo campo privato List<T> no? E' che tecnicamente non c'è modo...
    Per il problema di prima ho risolto passando come hai detto un array, non era un problema per carità, l'ultimo post era solo una cosa che mi chiedevo concettualmente...

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Kaamos
    intendevo dire che concettualmente la Class<T> potrebbe sapere T, gli basterebbe prendere il tipo di uno degli elementi del suo campo privato List<T> no?
    Nì ... tecnicamente sì ma concettualmente no. Io istanzio un TuaClasse<Number> che contiene un List<T> e ci infilo dentro un Integer, un Double, un Long (tutti dei Number).... cosa puoi dedurre come tipo?

    Originariamente inviato da Kaamos
    E' che tecnicamente non c'è modo...
    I modi generalmente sono due: o passi un array T[] in modo che si possa dedurre il tipo dall'array oppure esiste anche la possibilità di passare quello che viene chiamato un "class token". Il metodo riceve un Class<T> e tu gli passi es. String.class.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Utente di HTML.it
    Registrato dal
    Dec 2009
    Messaggi
    613
    Ah già, non avevo pensato alle sottoclassi, è vero.
    Grazie ancora, posterò ancora qui se l'argomento mi darà altre noie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.