Tipi generici

di Anonimizzato12154 il
6 risposte
Ciao a tutti,ho scritto questa classe:
public class Vettore<T> {
    T[] array;
    public Vettore(int capacità) {
        array=(T[])new Object[capacità]
    }
    //.... altri metodi
}
poi ho in un'altra classe questi metodi:

public static bubbleSort(Comparable[] c) {
    // corpo
}

public static bubbleSort(Vettore<Comparable> v) {
 // corpo
}
dove Comparable è l'interfaccia presente in java.lang

se in un main scrivo:
Vettore<Integer> i=new Vettore<Integer>(5);
// i metodi add() sono di Vettore
i.add(5);
i.add(2);
i.add(3);

bubbleSort(i) // qui ho un errore
in pratica l'errore che mi viene segnalato è che i di tipo Vettore<Integer> non è un Comparable[].
perchè succede questo?
i non è un Vettore<Comparable> visto che Integer implementa Comparable?
perchè bubbleSort chiama il metodo overloaded con parametro Comparable[] c?

6 Risposte

  • Guarda bene quello che hai scritto:
    public class Vettore<T> {
        T[] array;
        public Vettore(int capacità) {
            array=(T[])new Object[int capacità]
        }
        //.... altri metodi
    }
    vedi la castronata?
    Che cosa stai castanto? Perche''? Ma se fosse cosi', a che servirebbe <T>?
  • In che senso, quel casting serve a creare un array di T,visto che l'inizializzazione esplicita con T non è permessa.
  • Il problema è che un Vettore<Integer> non è un Vettore<Comparable>, non lasciarti confondere dai generici.

    Un Vettore<Comparable> può contenere qualunque tipo di oggetto che implementi Comparable (Integer, String, Double, quel che ti pare che implementa Comparable). Supponiamo, quindi, di avere un Vettore<Comparable> di questo tipo:
    
    Vettore<Comparable> v = new Vettore<Comparable>();
    v.add( 5 );   // Ammesso: Integer è Comparable
    v.add( "Ciao" ) ;   // Ammesso: String è Comparable
    v.add( new Date() );   // Ammesso: Date è Comparable
    
    Questo oggetto non contiene SOLO Integer, quindi è diverso da un Vettore<Integer> e non è nemmeno assegnabile (per ovvie ragioni). Quindi, Vettore<Integer> e Vettore<Comparable> sono oggetti completamente differenti.

    Che succederebbe se fossero assegnabili? Bene... io ho un metodo che accetta un Vettore<Comparable> e gli passo un Vettore<Integer>. Chi mi vieta di fare questo?
    
    Vettore<Integer> v = new Vettore<Integer>();
    metodo( v );
    
    ...
    
    public void metodo(Vettore<Comparable> v) {
       v.add("Ciao");
    }
    
    Se io potessi passare il mio vettore di interi ad un metodo che accetta un vettore di Comparable, nessuno mi vieterebbe di "rovinare" il vettore inserendovi delle stringhe... e questo è assolutamente contrario ad ogni logica di type-checking.

    Quello che serve a te è un modo per indicare al compilatore che il tuo metodo accetta un Vettore composto di tipi Comparable. E lo si fa con i bounded wildcard:
    
    public static void bubbleSort(Vettore<? extends Comparable> v) {
       ... // Corpo del metodo
    }
    
    In questo caso, il metodo bubbleSort() accetterà qualunque vettore contenente dei comparable.

    Ciao.
  • In realta' un'espressione del tipo:
    Vector<Comparable> v = new Vector<Integer>()
    sarebbe concettualmente valida in un linguaggio che supporta il concetto di covarianza in senso piu' generale di quanto viene fatto correntemente.

    Il concetto di covarianza e' quello che permette di fare un'assegnazione del tipo:
    Oject o = 5
    perche' '5' (un intero) e' un tipo piu' specializzato di 'Object' (tipo base per tutte le tipologie di dati/oggetti). Concettualmente e' sempre possibile passare da un tipo specifico ad un tipo piu' generale. L'operazione contraria, invece, non sempre ha senso. QUando supportata, si parla di controvarianza.

    Certo, ci sono delle conseguenze nel supportare un concetto del genere (appunto, rovinare un Vector<Integer>), e poiche' e' complicato, ci sono pochissimi linguaggi che lo supportano (Haskell se ricordo bene).
  • xneo ha scritto:


    in che senso, quel casting serve a creare un array di T,visto che l'inizializzazione esplicita con T non è permessa.
    Infatti, non e' permessa, ma questo, anche se sembra funzionare, in realta e' fittizzio:
    
    import java.lang.reflect.Array;
    
    class V<T>
    {
        T[] v;
    
        V(int l)
        {
             v = (T[])new Object[l];
        }
    
    
        T[] vect()
        {
            return  v;
        }
    }
    
    public class Main {
    
        public static void main(String[] args) {
    
            V<Integer> v = new V<Integer>(10);
    
            int i = v.vect()[1]; // badabum!!!!
        }
    }
    
    Invece, quello che si deve utilizzare, e' Array.newInstance(...)
    v = Array.newInstance(T.class, l)
    (nota: il codice cosi' non compila !!)

    Ora il problema e' ricuperare 'T.class'. Questo puo' essere fatto via Reflection sulla classe 'V<T>'.
  • Migliorabile ho capito quello che vuoi dire,
    questo pericolo non si otterrebbe se scrivessi anche:
    Integer[] v=(Integer[])Object[10];

    questa cosa credo dipenda dal buon senso del programmatore.

    il mio problema era un altro(e ringrazio leleft).
    in pratica io pensavo che un Vettore<Integer> era anche un Vettore<Comparable>.
Devi accedere o registrarti per scrivere nel forum
6 risposte