PDA

View Full Version : [Java] Gestire liste senza conoscerne il tipo?


Deep thought
10-08-2013, 19:40
Saluton a voi utenti,
Sto studiando Java e vorrei chiedervi un soccorso su un certo esercizio del mio libro di testo.
Prima di tutto ho risolto questo:
Si scriva un metodo generico soloPari() che, ricevuto un array a i cui elementi sono di un qualunque tipo T, restituisca un array composto dei soli elementi di indice pari all'interno di a. Per esempio: se x è l'array {1,5,10,100,4} il risultato di soloPari(x) sarà {1,10,4}.

È un esercizio abbastanza facile, che ho svolto con un metodo generico.
Quello che non sono riuscito a fare è il successivo, che dice:
Si scriva una variante di soloPari() che accetti come argomento una qualunque sequenza, e non necessariamente un array.

La mia domanda è: anche usando un metodo generico, come si può gestire una sequenza di cui non si sa il tipo (e che quindi può essere array, ArrayList, Vector, String, LinkedList eccetera)? Anche ammesso di riuscire a farla passare fra i parametri, bisogna poi manipolarla con i metodi d'istanza, che cambiano di volta in volta.

Chi mi aiuta verrà molto ringraziato per la sua gentilezza!

[Kendall]
11-08-2013, 10:25
Saluton a voi utenti,
Sto studiando Java e vorrei chiedervi un soccorso su un certo esercizio del mio libro di testo.
Prima di tutto ho risolto questo:


È un esercizio abbastanza facile, che ho svolto con un metodo generico.
Quello che non sono riuscito a fare è il successivo, che dice:


La mia domanda è: anche usando un metodo generico, come si può gestire una sequenza di cui non si sa il tipo (e che quindi può essere Array, ArrayList, Vector, String, LinkedList eccetera)? Anche ammesso di riuscire a farla passare fra i parametri, bisogna poi manipolarla con i metodi d'istanza, che cambiano di volta in volta.

Chi mi aiuta verrà molto ringraziato per la sua gentilezza!

Allora, premetto che non sono un esperto di java, ma in questo linguaggio dovrebbe esserci l'equivalente dell'interfaccia IEnumerable<T> del C# (se non erro in java è Iterable<T>.

Il concetto è abbastanza semplice, io parlo di C# ma credo che pari pari si possa traslare al java (un occhiata alle api ti aiuterà comunque).
IEnumerable espone dei metodi per elencare un un oggetto qualsiasi (se la relativa classe implementa l'interfaccia). Come è spontaneo supporre praticamente tutte le classi "contenitore" implementano tale interfaccia, quindi tu puoi enumerare un qualsiasi array, lista o altro contenitore generico creando un metodo che accetti come argomento un IEnumerable<Object> (o nel tuo caso Iterable<Object>).

Deep thought
11-08-2013, 21:07
Grazie Kendall, la tua idea mi sarà d'aiuto. La cosa strana è che al punto del libro a cui sono arrivato io le interfacce non sono state ancora introdotte. Mi sembra anche difficile che in un esercizio si debba usare un'interfaccia mai nominata, da cercare nell'API. Che sia una svista degli autori?

[Kendall]
12-08-2013, 06:19
L'unica altra alternativa che mi viene in mente è l'utilizzo di quello che in c# è l'identificatore params, posto prima dell'argomento della funzione (sempre nell'ultima posizione).
Su java è chiamato varargs e si utilizza ponendo nel modello di funzione il tipo seguito da una ellipsis ("...").
Nel tuo caso:

public Object[] soloPari(Object... args)
{
...
}

hollywoodundead
12-08-2013, 22:03
Grazie Kendall, la tua idea mi sarà d'aiuto. La cosa strana è che al punto del libro a cui sono arrivato io le interfacce non sono state ancora introdotte. Mi sembra anche difficile che in un esercizio si debba usare un'interfaccia mai nominata, da cercare nell'API. Che sia una svista degli autori?

Che libro stai studiando,forse posso darti una mano perchè siamo sulla stessa barca. ;)

Deep thought
13-08-2013, 08:35
;39826105']L'unica altra alternativa che mi viene in mente è l'utilizzo di quello che in c# è l'identificatore params, posto prima dell'argomento della funzione (sempre nell'ultima posizione).
Su java è chiamato varargs e si utilizza ponendo nel modello di funzione il tipo seguito da una ellipsis ("..."\).
Nel tuo caso:

public Object[] soloPari(Object... args)
{
...
}

Sì, quelli in Java si chiamano metodi variadici, e trattano una serie di parametri passati come se fossero un array; il problema è che se passo come argomento una qualsiasi lista ottengo un semplice array Object di lunghezza 1 che contiene, in posizione 0, la lista passata.




Che libro stai studiando,forse posso darti una mano perchè siamo sulla stessa barca. ;)

Davvero? Io sto studiando "Programmazione in Java"di Apogeo, e tu?

hollywoodundead
13-08-2013, 10:22
Sì, quelli in Java si chiamano metodi variadici, e trattano una serie di parametri passati come se fossero un array; il problema è che se passo come argomento una qualsiasi lista ottengo un semplice array Object di lunghezza 1 che contiene, in posizione 0, la lista passata.






Davvero? Io sto studiando "Programmazione in Java"di Apogeo, e tu?

Io sto studiando su Core java I the Fundamentals, però credo di non essere ancora arrivato tanto lontano per risolvere il secondo problema senza battere ciglio(devo ancora arrivare agli array). Possiamo comunque provare a ragionarci su. Il problema chiede di leggere una qualunque tipo di sequenza che sia un array etc.. in rete ci sono diverse spiegazioni su come utilizzare varargs, per esempio prova a leggere qui:

https://today.java.net/pub/a/today/2004/04/19/varargs.html

Per completezza posta anche come hai risolto il primo esercizio, in quanto il secondo è solo un estensione del primo e bisogna aggiungere come argomenti le altre tipologie di sequenze esistenti in java :)

Deep thought
14-08-2013, 10:38
Scusa per il ritardo.
Per quanto riguarda il primo esercizio, l'ho risolto con questo codice:

public static <T> Object[] soloPari(final T[] inputArray) {
Vector<T> outputVector = new Vector<T>();
for (int i=0; i<inputArray.length; i++) {
if (i%2 == 0) outputVector.add(inputArray[i]);
}
Object[] outputArray = new Object[outputVector.size()];
for (int i=0; i<outputVector.size(); i++) {
outputArray[i] = outputVector.get(i);
}
return outputArray;
}


Temo che, se non sei ancora arrivato agli array (e quindi nemmeno ai vettori) possa essere un po' problematico. È un metodo generico che chiede come parametro un array di tipo qualsiasi (indicato con T) e crea un vettore outputVector di tipo T che contiene solo gli elementi di indice pari (cioè posizione nella lista). Quindi crea un array outputArray di tipo Object, lo riempie con i valori del vettore outputVector e lo restituisce come risultato.
Per quanto riguarda i varargs ho letto l'articolo e so come usarli, ma non mi possono essere utili qui perché l'esercizio chiede di creare un metodo che possa avere come argomento una lista, e non un numero imprecisato di dati. Cioè, il metodo che io devo scrivere deve essere tale da essere chiamato non così:

soloPari (0, 2, 3456, 1);

che è appunto ciò che si fa con i metodi variadici; al contrario, io devo chiamarlo in questo modo:

soloPari (array);
soloPari (Vector);
soloPari (LinkedList);
...


Quindi, che fare? L'unica cosa che mi viene in mente è scrivere un metodo sovraccarico per ogni tipo di lista possibile in Java, ma mi pare praticamente impossibile, perché io so che esistono Array, Vector, LinkedList, List e ArrayList, ma ce ne sono anche tante altre; per non parlare poi di quelle provenienti da API non ufficiali e tutto il resto.

P.S. Hollywoodundead, è difficile studiare un libro del genere in inglese? Ci vuole un'ottima conoscenza della lingua, vita all'estero e cose simili? E come mai lo preferisci a quelli in italiano?

hollywoodundead
14-08-2013, 13:11
@Deep

Per il secondo esercizio avevo pensato alla stessa soluzione da te proposta, cioe assegnare un metodo per ogni tipologia di lista presente in java ma come dici bene tu mi pareva una cosa troppo complicata da fare e in quel caso avrei dovuto dare come risposta "impossible for me". Per quanto riguarda varargs ho pensato che come soluzione non era male quella di passare come argomenti le diverse tipologie di liste in java, ma anche qui avevo i miei dubbi che la cosa funzionasse, visto che non sono nemmeno arrivato a studiare gli array. Il libro che studio l'ho scelto primo perchè capisco piu che bene sia in lettura che ascolto la lingua inglese ( poi per i termini tecnici basta un buon dizionario di fianco) e secondo perchè mi sono letto in pdf gli altri libri italiani, e non mi hanno molto entusiasmato. Alcuni di questi sono:

1)Dai fondamenti agli oggetti: corso di programmazione java di Pighizzino (questo è il libro che utilizzano nella facoltà dove andrò a studiare :doh: ) che mi è parso dalla lettura molto riduttivo nel spiegare le cose e ti butta in pasto gli esercizi come se il metodo di apprendimento fosse quello di memorizzare i blocchi di codice senza capirne il reale significato. Oltretutto le mie impressioni combaciano anche con alcuni commenti postati su amazon.

2)Programmazione Java 1 di Deitel, il commento su amazon è micidiale e non serve aggiungere altro. L'edizione in italiano pare sia stata tradotta in maniera terribile e che i capitoli siano stati organizzati in maniera diversa rispetto alla versione inglese, creando maggiore confusione.

3)Manuale di Java 6 di Claudio de sio cesari: questo è un peccato, perchè l'ho letto per almeno il primo capitolo e inizialmente parte bene solo che lo trovo ridondante e confusionario. I concetti vengono spiegati utilizzando duemila sinonimi diversi per spiegare la stessa cosa e credimi alla fine ti manda nel pallone senza capire bene quello che all'inizio del discorso spiegava chiaramente. Insomma parte bene spiegandoti il concetto e poi ti confonde i concetti iniziali esposti con parole che avrebbe potutto benissimo evitare. Se volessi capirlo bene credo che dovrei leggerlo almeno 3 volte :D

Ci sono altri libri che avrei voluto vedere com'erano ma non li ho trovati in rete e non avevo tempo per andare a vederli in libreria. Tra questi ci sono Programmazione in java di Roberto bruni,Java2 in tasca di loic fieux (per principianti) Il linguaggio java di Gosling James (anche qui la traduzione italiana e di conseguenza gli eventuali errori presenti mi spaventano) e infine Programmazione con java di Savitch Walter.

Sull'ultimo libro si Savitch mi piacerebbe sentire qualche parere, perchè pare che la traduzione in italiano non sia stata fatta male, quindi forse andrò a vederlo in libreria.

Ho scelto alla fine Core Java I the fundamentals perchè è quello in cui non ho riscontrato pareri negativi su amazon, e sopratutto perchè è spiegato bene.Non è fatto proprio per chi è principiante, ma va benissimo anche per chi inizia ad imparare questo linguaggio ad un livello tra il principiante e il medio. Io mi trovo bene, è un libro lungo perchè ci sono piu di 800 pagine da leggere, quindi magari se qualcuno vuole metterci meno tempo deve ripiegare su altri libri. Approfondisce molti aspetti che sicuramente altri libri non spiegano, e durante la spiegazione fa un confronto con delle note su quelle che sono le differenze con c++ su quel determinato argomento spiegato. Per me che punto ad imparare alla fine l'objc per diventare sviluppatore apple, è un buon inizio. ;)

Deep thought
14-08-2013, 13:34
Il libro che sto studiando io è proprio "Programmazione in Java" di Roberto Bruni, e mi sembra abbastanza serio ma al tempo stesso comprensibile. Questa è la prima volta che mi trovo in seria difficoltà. Temo proprio di dover ignorare questo esercizio, per ora, almeno finché non si smuove qualcosa.

hollywoodundead
14-08-2013, 14:14
Il libro che sto studiando io è proprio "Programmazione in Java" di Roberto Bruni, e mi sembra abbastanza serio ma al tempo stesso comprensibile. Questa è la prima volta che mi trovo in seria difficoltà. Temo proprio di dover ignorare questo esercizio, per ora, almeno finché non si smuove qualcosa.

Tu quale versione hai di Programmazione in java? la 2009 0 la 2011? sei sicuro che sia spiegato bene? perchè se uno ti mette un esercizio da fare si presume che ti abbia spiegato prima i concetti che servono per farlo non dopo. :)

Deep thought
14-08-2013, 17:15
Ho l'edizione del 2011. La lezione l'ho capita bene, e ho anche riletto le parti interessate; secondo me il problema è proprio impossibile, o qualcun altro leggermente più esperto di noi due avrebbe già dato una risposta risolutiva (è pur sempre un esercizio). Sarà stato un errore.

Deep thought
14-08-2013, 17:16
Ho l'edizione del 2011. La lezione l'ho capita bene, e ho anche riletto le parti interessate; secondo me il problema è proprio impossibile, o qualcun altro leggermente più esperto di noi due avrebbe già dato una risposta risolutiva (è pur sempre un esercizio di un libro di testo, non dovrebbe essere difficile per altri). Sarà stato un errore.

mone.java
14-08-2013, 18:52
public static <T> Collection<T> soloPari(Collection<T> inputArray) {
List<T> outputList = new ArrayList<T>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) outputList.add(elem);
i++;
}

return outputList;
}


forse quello che vi serve è questo se volete comprendere tutte le collezioni di java (Array, Vector, LinkedList, List e ArrayList ecc...)

hollywoodundead
14-08-2013, 18:54
Ho l'edizione del 2011. La lezione l'ho capita bene, e ho anche riletto le parti interessate; secondo me il problema è proprio impossibile, o qualcun altro leggermente più esperto di noi due avrebbe già dato una risposta risolutiva (è pur sempre un esercizio di un libro di testo, non dovrebbe essere difficile per altri). Sarà stato un errore.

Di esperti d'estate non trovi nessuno :D, ritornano a settembre ottobre come di solito. Comunque dall'indice del libro immagino che tu sia almeno a metà del libro, magari la soluzione la trovi piu avanti :). Riuppalo per settembre, magari qualche esperto è già tornato dalle vacanze e lo risolve in un batter d'occhio. A me interessa saperla la soluzione, non mi piace lasciare le cose per non fatte, quindi, per adesso non sono di grande aiuto perchè sono agli inizi, pero piu in là chissà ;)

hollywoodundead
15-08-2013, 12:41
public static <T> Collection<T> soloPari(Collection<T> inputArray) {
List<T> outputList = new ArrayList<T>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) outputList.add(elem);
i++;
}

return outputList;
}


forse quello che vi serve è questo se volete comprendere tutte le collezioni di java (Array, Vector, LinkedList, List e ArrayList ecc...)

Ciao :) , potresti riscriverlo con un esempio concreto, sostituendo quelle T, cosi per renderlo piu comprensibile ;)

mone.java
15-08-2013, 19:11
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);

Collection<Integer> pari = soloPari(list);

for(Integer i : pari) {
System.out.println(i);
}
}

hollywoodundead
15-08-2013, 22:03
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);

Collection<Integer> pari = soloPari(list);

for(Integer i : pari) {
System.out.println(i);
}
}


Inanzitutto ho trovato indicativamente,se non tutte,le collections framework qui: http://docs.oracle.com/javase/6/docs/technotes/guides/collections/reference.html

Nel programma che hai scritto,hai utilizzato un ciclo for each loop,dove crei una sequenza List che chiami list, di tipo intero con al suo interno un metodo array(che contiene quella sequenza di numeri che hai messo). Poi crei una Collection Framework che chiami pari, di tipo intero, a cui passi il metodo soloPari() (come mai non hai riportato per chiarezza, anche il metodo solopari() postato da deep?) che va a interagire con l'oggetto list. Infine con un ciclo for each loop vai a dire per ogni elemento i, intero, passato nella colletcion pari, vai ad eseguire la stampa...però non mi tornano alcuni passaggi.

1)"i" dove l'hai dichiarata per collegarla agli elementi dell'array?
2)Il programma scritto cosi, è completo o manca appunto da aggiungere il metodo soloPari() e altri pezzi di codice?

Secondo me la domanda da farsi è: esiste una oggetto o funzione che inglobi in un colpo solo tutti i tipi di Collections framework in modo tale da passarci solo quello come argomento del metodo soloPari()? altrimenti ritorniamo punto a capo,cioè che bisogna aggiungere ogni singola Collections come argomento del metodo soloPari() :)

mone.java
16-08-2013, 06:51
1) l'ho dichiarata esattamente dove la vedi

//DIchiaro i e assegno ad ogni iterazione il valore successivo contenuto in pari
//studiati il foreach in java comunque
for(Integer i : pari)


2)manca soloPari() che ho scritto nel post precedente metti assieme soloPari() e main() in una classe ed esegui..

3)Si questo oggetto (sarebbe meglio dire classe) esiste e si chiama per l'appunto Collection... Infatti a soloPari ci puoi passare sia un ArrayList che una LinkedList che un Set ecc... in parole povere tutte le collezioni che java ci mette a disposizione...

ti posto il programma intero:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
*
* @author Simone Rondelli - mone.java[at]gmail.com
*/
public class Main {

public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);

Collection<Integer> pari = soloPari(list);

for (Integer i : pari) {
System.out.println(i);
}
}

public static <T> Collection<T> soloPari(Collection<T> inputArray) {
List<T> outputList = new ArrayList<>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) {
outputList.add(elem);
}
i++;
}

return outputList;
}
}



al posto di list ci puoi mettere una qualunque collezione java...

Deep thought
23-08-2013, 11:30
Scusate per la lunga assenza, ma sono stato in vacanza e non ho usato Internet per una settimana.
@mone.java
Grazie, questo è proprio quello che mi serviva! Sicuramente da solo non ci sarei mai arrivato, perché non ho mai avuto a che fare con le Collection né sapevo che esistessero. Se ho capito bene, la classe Collection è una specie di classe generica che dà un supporto a tutti i tipi di liste (perdonami per il linguaggio in cui mi esprimo, da novellino)?
Poi tu hai creato un metodo generico che prende come argomento una lista qualsiasi e restituisce un oggetto List; il tipo del metodo è Collection<T>, ma il tipo della variabile di ritorno outputList è List, quindi il tipo di ritorno sarà List, vero?

EDIT: L'API di Java dice che Collection è un'interfaccia, e io le interfacce non le ho ancora studiate. Che sono?

EDIT2: Forse sto capendo qualcosa: il metodo generico soloPari è di qualunque tipo T che implementi l'interfaccia Collection, giusto? Ma allora in questo caso non si sarebbe dovuto scrivere, nell'intestazione del metodo, public static <T extends Collection<T>> soloPari?

mone.java
23-08-2013, 12:01
In java un interfaccia è una sorta di classe che definisce il comportamento (per l'appunto interfaccia) di "qualcosa" senza darne un implementazione. Collection definisce il comportamento delle collezioni ArrayList Vector ecc.. implementano Collection (direttamente o indirettamente) e ne implementano i metodi ovvero concretizzano il comportamento... MA comunque dovresti studiarti l'ereditarietà per capire bene...

=> Quindi un ArrayList e un Vectior hanno lo stesso comportamento in uanto entrambi implementano Collection ma lo implementano in modi diversi. NEssuno ti impedisce di fare una tuo tipo che implementa Collection.

Questo di permette di fare conversioni implicite tra tipi (upcasting http://forum.codecall.net/topic/50451-upcasting-downcasting/) siccome List sicuramente rispetta Collection io posso scrivere:

Collection t = new ArrayList();

oppure

List l = new ArrayList();
Collection c = l;

Capito?

Detto questo Collection<T> significa che quella è una collezione di oggetti di tipo T quindi se scrivo Collection<Integer> List<String> List<List> sto parlando di

Collection<Integer> -> collezione di interi
List<String> -> Lista di stringhe
List<List> -> Lista di Liste

Quindi quello che hai scritto non ha molto senso..

Deep thought
23-08-2013, 12:16
Perché la clausola extends non ha molto senso? Il mio libro dice che serve a restringere il tipo T di un metodo generico alle sole classi che implementino una certa interfaccia.
Ad esempio, nel metodo public static <T extends Comparable <T>> T max(T...n) io posso passare come argomento qualsiasi variabile di tipo T purché T implementi l'interfaccia Comparable.
Quindi, allo stesso modo, se io il metodo soloPari lo presentassi così: public static <T extends Collection<T>> soloPari(T inputList) avrei un metodo generico che richiede come argomento un oggetto qualunque che implementa l'interfaccia Collection, il cui tipo di ritorno è il tipo stesso del parametro passato, cioè T.

mone.java
23-08-2013, 13:30
Perche con <T extends Collection<T>> Stai dicendo che il Tipo di ritorno è qualcosa che estende una collezione di oggetti di tipo collezione... ciè è corretto ma non penso sia il tuo caso... Potresti ad esempio passarci un List<List>....

non so se mi spiego...

Deep thought
23-08-2013, 13:33
Allora, ho provato la tua versione di soloPari passando come argomento un array di stringhe in questo modo:

public static void main (String[] args) {
String[] argsPari = soloPari(args);
for (String s:argsPari) {
System.out.println(s);
}
}

Ma ottengo questo errore in fase di compilazione:

SoloPariGenerico.java:6: error: method soloPari in class SoloPariGenerico cannot be applied to given types;
String[] argsPari = soloPari(args);
^
required: Collection<T>
found: String[]
reason: no instance(s) of type variable(s) T exist so that argument type String[] conforms to formal parameter type Collection<T>
where T is a type-variable:
T extends Object declared in method <T>soloPari(Collection<T>)
1 error


----------------------------------------------------------------------------------------------------------------------------------------------

Quello che ho in mente io è un metodo che usa la clausola extends e l'interfaccia List. Ho scritto questo:

public static <T extends List<T>> T soloPari(T input) {
T output = new ArrayList();
for (int i = 0; i<input.size(); i++) {
if (i % 2 == 0)
output.add(input.get(i));
}
return output;
}

Ma ottengo questo errore:

SoloPariGenerico.java:15: error: incompatible types
T output = new ArrayList();
^
required: T
found: ArrayList
where T is a type-variable:
T extends List<T> declared in method <T>soloPari(T)
1 error

Se, come hai detto, un'interfaccia (in questo caso List) rende compatibili tipi diversi, perché tra i tipi T ed ArrayList non è permesso il casting automatico?

--------------------------------------------------------------------------------------------------------------------------------------------------

Perche con <T extends Collection<T>> Stai dicendo che il Tipo di ritorno è qualcosa che estende una collezione di oggetti di tipo collezione... ciè è corretto ma non penso sia il tuo caso... Potresti ad esempio passarci un List<List>....

non so se mi spiego...

Non penso che il diamante <> in Collection<T> indichi che quella è una lista... infatti nel mio libro c'è l'esempio di <T extends Comparable<T>>, che non c'entra affatto con le liste ma funziona.

EDIT: E se invece scrivessi semplicemente <T extends List>?

mone.java
23-08-2013, 13:45
<T extends Collection> -> Significa che il tipo T estende/implementa collection...
Collection<T> -> Significa che la collezione contiene oggetti di tipo T...
<T extends Collection<T>> -> Significa che t è una collezione che contiene collezioni...

TU nell'esempio che mi fai vedere sbagli perchè stai cercando di passare un array CHE NON È UNA COLLEZIONE NE TANTOMENO UNA LISTA... UN ARRAY È UN ARRAY... quindi non riuscirai mai a fare un metodo che prende sia array che liste a meno che tu non faccia un metodo che prende in input un Object e poi controlli i tipi:


public static <T> Collection<T> soloPari(Object input) {
if (input instanceof Collection) {

}
}

Deep thought
23-08-2013, 15:03
Come, gli array non sono compatibili con le altre liste?!?!?? Come le vengo a sapere, certe cose!
E adesso che faccio? L'esercizio chiede che il metodo funzioni con qualsiasi sequenza.
A proposito: String implementa Collection?
Continuando invece a provarci con i metodi generici: <T extends Collection> potrebbe andare bene per il metodo che avevo scritto io? Il metodo diventerebbe così:

public static <T extends List> T soloPari(T input) {
T output = new ArrayList();
for (int i = 0; i<input.size(); i++) {
if (i % 2 == 0)
output.add(input.get(i));
}
return output;
}

Ovvero: io richiamo il metodo soloPari passando come parametro un qualsiasi oggetto istanza di una classe che implementi l'interfaccia List; io creo un oggetto dello stesso tipo T che contiene solo gli elementi di indice pari e lo restituisco per risultato.
Ma l'errore che ottengo è lo stesso di prima: dice che T e ArrayList non sono compatibili.

P.S. Ti faccio notare che l'approccio è diverso da quello che mi hai suggerito tu, perché nel tuo metodo T è il tipo degli oggetti contenuti nella collezione, mentre nel mio metodo T è il tipo stesso della lista passata come parametro.

mone.java
23-08-2013, 15:10
Postami il codice completo! e comunque sia se lo vuoi fare il più generico possibile allora allora usa Collection anzichè List...

I sottotipi di collection sono:

BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>, Deque<E>, List<E>, NavigableSet<E>, Queue<E>, Set<E>, SortedSet<E>... Che come vedi comprendono anche List....

Cmq non capisco dove vuoi arrivare dal momento che non esiste un tipo compatibile sia con Array che con collections ( a parte object)...

Deep thought
23-08-2013, 15:32
Quello era il codice completo del metodo, ovviamente da richiamare con un metodo main.
La classe dovrebbe essere qualcosa del genere:

import java.util.List;
import java.util.ArrayList;
import java.util.Vector;

public class SoloPariGenerico {
public static void main (String[] args) {
Vector<String> v = new Vector<String>(); // crea un vettore
for (String s:args) {
v.add(s); // lo riempie
}
Vector<String> pari = soloPari(v); // invoca il metodo
// magari qui lo stampa, ecc.
}

public static <T extends List> T soloPari(T input) {
T output = new ArrayList();
for (int i = 0; i<input.size(); i++) {
if (i % 2 == 0)
output.add(input.get(i));
}
return output;
}
}

Ovviamente il vettore usato nel metodo main è solo per fare una prova delle funzioni del metodo, ma dovrebbe poter essere una qualsiasi lista.
Per quanto riguarda gli array per il momento lasciamo perdere: visto che non implementano List né Collection li potrei gestire in un altro metodo attraverso l'overloading.
Mi chiedi perché usare l'interfaccia List e non Collection: perché con Collection non funge il metodo add e quindi non posso riempire la lista.

mone.java
23-08-2013, 16:09
Mha ti posto entrambe le soluzioni... non capisco perchè vuoi a tutti i costi usare T extnds List... in questo frangente non ha senso... ha molto più senso Usare Collection<T>... degustibus...


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
*
* @author Simone Rondelli - mone.java[at]gmail.com
*/
public class Main {

public static void main(String[] args) {
List<Integer> list = new ArrayList<>();

for (int i = 0; i < 10; i++) {
list.add(i);
}

Collection<Integer> pari = soloPari1(list);

for (Integer i : pari) {
System.out.println(i);
}

List pari2 = soloPari2(list);

for (Object i : pari2) {
System.out.println(i);
}

}

public static <T> Collection<T> soloPari1(Collection<T> inputArray) {
List<T> outputList = new ArrayList<>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) {
outputList.add(elem);
}
i++;
}

return outputList;
}

public static <T extends List> T soloPari2(T input) {
T output = (T) new ArrayList();

for (int i = 0; i<input.size(); i++) {
if (i % 2 == 0)
output.add(input.get(i));
}
return (T) output;
}
}

Deep thought
23-08-2013, 19:16
Semplicemente perché l'esercizio è sui metodi generici, e non devo abusare delle interfacce finché non le studio seriamente. Comunque:
Finalmente ho capito, aggiungendo il casting esplicito

Vector<T> vec = new Vector(Arrays.asList(arr));
ERRATA CORRIGE: mi riferivo a
T output = (T) new ArrayList();

compila! :D
Ma dà un errore a esecuzione. :(
Il codice completo è questo:

import java.util.List;
import java.util.Vector;
import java.util.Arrays;
import java.util.ArrayList;
public class SoloPariGenerico {
public static void main (String[] args) {
String[] argsPari = soloPari(args);
for (String s:argsPari) {
System.out.println(s);
}
}

// Gestisce le liste
public static <T extends List> T soloPari(T input) {
T output = (T) new ArrayList();
for (int i = 0; i<input.size(); i++) {
if (i % 2 == 0)
output.add(input.get(i));
}
return (T) output;
}

// Gestisce gli array
public static <T> T[] soloPari(final T[] arr) {
Vector<T> vec = new Vector(Arrays.asList(arr));
Vector<T> pari = soloPari(vec);
T[] output = (T[]) new Object[pari.size()];
int i = 0;
for (T elem:pari) {output[i]=elem; i++;}
return output;
}
}


E l'errore è proprio nel casting:

Exception in thread "main" java.lang.ClassCastException:
java.util.ArrayList cannot be cast to java.util.Vector

mone.java
25-08-2013, 08:30
Questo non è un cast esplicito...

Vector<T> vec = new Vector(Arrays.asList(arr));

qui semplicemente sfrutti il vatto che la classe vector (come molte altre del framework collections) ha un costruttore che prende in input una Collection (guarda caso Collection non List) http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html e da essa costruisce un vettore con gli elementi ordinati nell'ordine con cui vengono restituiti dall'iterator della collecion stessa.

Comunque ti sconsiglio di usare Vector alcuni IDE li considerano addirittura obsoleti e ne sconsigliano l'uso... (guarda qui http://www.javacodegeeks.com/2010/08/java-best-practices-vector-arraylist.html e qui http://javarevisited.blogspot.it/2011/09/difference-vector-vs-arraylist-in-java.html) sopratutto le performance sugli Iterator... Usa le liste....

Exception in thread "main" java.lang.ClassCastException:
java.util.ArrayList cannot be cast to java.util.Vector

Te lo da perchè tu stai passando a un metodo che opera con le Liste un Vector


T output = (T) new ArrayList();


DIventa


Vector output = (Vector) new ArrayList();


Il tutto funzionerebbe se tu usassi le Collection come ti avevo fatto vedere nel primo esempio...

mi devi ancora spiegare perchè vuoi fare a tutti i costi


T extends List


?

Tudovresti lavorare con Collection<T> !!!! e non <T extends List>!!!!

Deep thought
25-08-2013, 17:54
Ops, scusa, parlando del casting esplicito mi riferivo proprio a

T output = (T) new ArrayList();

ma ho inavvertitamente copiato la riga di codice sbagliata.

Mi ricorderò di non usare Vector, ma al momento il tipo che passo come parametro non ha influenza: infatti il metodo soloPari deve funzionare su qualunque tipo, e se non funziona su Vector non funzionerà nemmeno su LinkedList o un'altra sequenza.
Non posso usare Collection<T> perché, come ti ho già detto, non ho ancora studiato le interfacce e non posso usare "trucchetti" per risolvere gli esercizi. L'esercizio è nel capitolo sui metodi e, secondo le conoscenze che dovrei avere finora, posso risolverlo solo usando metodi generici e clausola "extends".
In più c'è un altro motivo: secondo quello che richiede la traccia, il metodo deve funzionare su qualsiasi tipo di sequenza. Se uso Collection<T>, invece, il tipo restituito cambia da Vector<T> (o ArrayList<T> o LinkedList<T>) a Collection<T>, che è un tipo molto più generico. Io devo continuare a operare sullo stesso tipo. Altrimenti sarebbe come chiedere a un utente un numero Integer per elevarlo al quadrato e prima di svolgere l'operazione convertirlo in Number o in Object.
A questo punto potresti chiedermi perché usare <T extends List> e non <T extends Collection>: il motivo è che Collection non implementa il metodo add.

[Kendall]
25-08-2013, 21:31
Ops, scusa, parlando del casting esplicito mi riferivo proprio a

T output = (T) new ArrayList();

ma ho inavvertitamente copiato la riga di codice sbagliata.

Mi ricorderò di non usare Vector, ma al momento il tipo che passo come parametro non ha influenza: infatti il metodo soloPari deve funzionare su qualunque tipo, e se non funziona su Vector non funzionerà nemmeno su LinkedList o un'altra sequenza.
Non posso usare Collection<T> perché, come ti ho già detto, non ho ancora studiato le interfacce e non posso usare "trucchetti" per risolvere gli esercizi. L'esercizio è nel capitolo sui metodi e, secondo le conoscenze che dovrei avere finora, posso risolverlo solo usando metodi generici e clausola "extends".
In più c'è un altro motivo: secondo quello che richiede la traccia, il metodo deve funzionare su qualsiasi tipo di sequenza. Se uso Collection<T>, invece, il tipo restituito cambia da Vector<T> (o ArrayList<T> o LinkedList<T>) a Collection<T>, che è un tipo molto più generico. Io devo continuare a operare sullo stesso tipo. Altrimenti sarebbe come chiedere a un utente un numero Integer per elevarlo al quadrato e prima di svolgere l'operazione convertirlo in Number o in Object.
A questo punto potresti chiedermi perché usare <T extends List> e non <T extends Collection>: il motivo è che Collection non implementa il metodo add.

Il fatto è che NON puoi costruire un metodo che funziona per ogni tipo di collezione senza usare una interfaccia.
E a dirla tutta neppure usando l'interfaccia riusciresti a prenderle dentro tutte, perchè ogni classe collezione implementa Collection<T> (e quindi Iterable<T>) ma non gli array.

(Non capisco poi perchè nei tuoi esempi hai comunque utilizzato List, che è essa stessa una interfaccia, seppure non generica, per lo meno per quanto ne so di Java, quindi non molto).

L'unica cosa secondo me è costruire un metodo che accetti un Iterable<T> (che è più generico di Collection<T> e viene implementato da praticamente ogni sequenza di elementi, a differenza di Collection<T> che è, seppure vastamente implementata, non quanto la sua interfaccia base, ed un overload dello stesso metodo che accetta un array.
Questa è l'unica vera soluzione generica che mi viene in mente (sempre che non mi sfugga qualcosa del Java, ripeto non lo conosco così bene).

mone.java
25-08-2013, 22:59
;39874257']Il fatto è che NON puoi costruire un metodo che funziona per ogni tipo di collezione senza usare una interfaccia.
E a dirla tutta neppure usando l'interfaccia riusciresti a prenderle dentro tutte, perchè ogni classe collezione implementa Collection<T> (e quindi Iterable<T>) ma non gli array.

(Non capisco poi perchè nei tuoi esempi hai comunque utilizzato List, che è essa stessa una interfaccia, seppure non generica, per lo meno per quanto ne so di Java, quindi non molto).

L'unica cosa secondo me è costruire un metodo che accetti un Iterable<T> (che è più generico di Collection<T> e viene implementato da praticamente ogni sequenza di elementi, a differenza di Collection<T> che è, seppure vastamente implementata, non quanto la sua interfaccia base, ed un overload dello stesso metodo che accetta un array.
Questa è l'unica vera soluzione generica che mi viene in mente (sempre che non mi sfugga qualcosa del Java, ripeto non lo conosco così bene).

Infatti Iterable è ancora meglio di collection siccome è ancor piu generico (Collection estende Iterable)...
Ma rimane il fatto che <T extends Collection|Iterable|List|ecc...> non serve a niente.. tu hai visto un esempio con l'interfaccia Comparable e li ha senso avere <T extends Comparable<T>> che significa che il tipo T implementa un Comparator per se stesso... ma nel caso delle liste non ha alcun senso perché significa una Collezione che contiene Collezioni... o una Lista che contiene Liste... con <T extends List> la lista può contenere qualunque cosa ma perdi comunque i vantaggi dei Generics...

Collection è vero non implementa il metodo add ma nessuno ti impedisce di fare come ti avevo fatto vedere:


public static <T> Collection<T> soloPari(Collection<T> inputArray) {
List<T> outputList = new ArrayList<T>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) outputList.add(elem);
i++;
}

return outputList;
}

Deep thought
26-08-2013, 17:31
@Kendall Ecco, esattamente quella che era la mia intenzione.
@mone.java Te l'ho già detto, devo usare gli strumenti che ho a disposizione dal mio studio. Altrimenti è come se in quinta elementare, per risolvere i problemi sui triangoli, mentre studiavo il teorema di Pitagora, avessi usato le funzioni trigoniometriche! E poi, te lo ripeto ancora (l'ho scritto nell'ultimo messaggio), il modello che tu dici non rispetta la traccia dell'esercizio.

<T extends Comparable<T>> che significa che il tipo T implementa un Comparator per se stesso... ma nel caso delle liste non ha alcun senso perché significa una Collezione che contiene Collezioni... o una Lista che contiene Liste... con <T extends List> la lista può contenere qualunque cosa ma perdi comunque i vantaggi dei Generics...

Infatti ti ho detto che quello era un errore, voglio usare <T extends List>.
Perché dici che perdo i vantaggi di Generics?
E perché dici che non ha senso? <T extends List> include tutti i tipi che implementano List, cioè tutte le liste.

mone.java
26-08-2013, 17:52
@mone.java Te l'ho già detto, devo usare gli strumenti che ho a disposizione dal mio studio.

E quali sarebbero gli strumenti se usi Comparable<T>|Iterable<T>|List<T> al posto di <T extends List> ?


Perché dici che perdo i vantaggi di Generics?


Perchè con <T extends List> non specifichi il tipo di dato che vai a mettere dentro alla lista.. Quindi puoi metterci dentro qualunque cosa (e salvo rari casi è sbagliato).. Questo comporta che quando prendi fuori gli oggetti dalla lista devi fare un cast esplicito per potervi accedere ai metodi specifici...

es:

/* senza generics */
List l = new ArrayList();
l.add(new Integer (1));
l.add("sono un stringa che non c'entra un tubo on gli interi");

Integer i = (Integer) l.get(0); // scomdo e soggetto a errori di cast a runtime
String s= (String) l.get(1); //altrettanto scomodo e soggetto a errori..

Integer i = l.get(0); //errore
String s = l.get(1); //errore
Integer i = (String) l.get(0); //errore e cosi via...

/* con generics */

List<Integer> l = new ArrayList<>();
l.add(new Integer (1));
l.add("sono un stringa che non c'entra un tubo on gli interi"); //errore!!!

Integer i = l.get(0); //molto comodo ed esente da errori di cast a runtime

//stessa cosa per le stringhe diciamo che ci siamo capiti



E perché dici che non ha senso? <T extends List> include tutti i tipi che implementano List, cioè tutte le liste.


È inutile visto che se scrivi che il metodo di input prende una Collection<T>, se vuoi usare i generics, altrimenti una Collection se non li vuoi usare, ci pensa il compilatore a fare il cast implicito da Liste, Set, Vector ecc... a Collection.. perchè il compilatore saprà che ad esempio List implementa Collection e cosi via.. gli vai a dare un informazione inutile...

Se scrivi Collection lui prende in imput tutti i tipi che implementano Collection comprese le Liste ecc...

[Kendall]
26-08-2013, 21:54
@Kendall Ecco, esattamente quella che era la mia intenzione.
@mone.java Te l'ho già detto, devo usare gli strumenti che ho a disposizione dal mio studio. Altrimenti è come se in quinta elementare, per risolvere i problemi sui triangoli, mentre studiavo il teorema di Pitagora, avessi usato le funzioni trigoniometriche! E poi, te lo ripeto ancora (l'ho scritto nell'ultimo messaggio), il modello che tu dici non rispetta la traccia dell'esercizio.

Infatti ti ho detto che quello era un errore, voglio usare <T extends List>.
Perché dici che perdo i vantaggi di Generics?
E perché dici che non ha senso? <T extends List> include tutti i tipi che implementano List, cioè tutte le liste.

Ma List è un'interfaccia! Pertanto non ha senso che tu la usi (visto che dici tu stesso che non puoi usare le liste).
Te lo ripeto, senza interfacce tu NON puoi creare un metodo che possa analizzare una sequenza di qualsiasi tipo.
Ergo o c'è qualcosa che mi sfugge o l'esercizio è mal posto o tradotto erroneamente (nel caso l'originale non fosse in italiano).

Deep thought
29-08-2013, 08:22
Mi arrendo, non c'è proprio modo. Avete ragione.
Quindi per risolvere è sufficiente il metodo che ha scritto tempo fa mone.java, vero?
Cioè

public static <T> Collection<T> soloPari(Collection<T> inputArray) {
List<T> outputList = new ArrayList<T>();
int i = 0;
for (T elem : inputArray) {
if (i % 2 == 0) outputList.add(elem);
i++;
}

return outputList;
}


Se è così, la discussione finisce qui. Ringrazio mone.java, [Kendall] e Hollywoodundead.

mone.java
29-08-2013, 08:35
Ciao Deep thought si basta quello... oppure come detto da Kendall al posto di Collection ci metti Iterator e cosi sei più generico.... :D ... TI dirò che anche io dopo anni che programmo (non troppi perchè comunque ho 23 anni) mi trovo spesso a sforzarmi di risolvere un problema che non ha soluzione... semplicemente perché magari mi pongo la domanda sbagliata... o faccio asserzioni sbagliate sulle capacità del linguaggio/libreria/ide/so oppure sulla filosofia che c'è dietro... È come tentare di arrivare a piedi in america... stai proprio sbagliando l'approccio al problema....

Saluti, Simone Rondelli.

Deep thought
29-08-2013, 17:12
Ciao Deep thought si basta quello... oppure come detto da Kendall al posto di Collection ci metti Iterator e cosi sei più generico.... :D ... TI dirò che anche io dopo anni che programmo (non troppi perchè comunque ho 23 anni) mi trovo spesso a sforzarmi di risolvere un problema che non ha soluzione... semplicemente perché magari mi pongo la domanda sbagliata... o faccio asserzioni sbagliate sulle capacità del linguaggio/libreria/ide/so oppure sulla filosofia che c'è dietro... È come tentare di arrivare a piedi in america... stai proprio sbagliando l'approccio al problema....

Saluti, Simone Rondelli.

Io sono ancora più giovane di te, e mi rendo spesso conto di questa situazione: ma è proprio per questo che la programmazione mi sembra così bella, le possibilità infinite di considerare un problema e, in un qualche modo, di creare qualcosa. È stato un piacere ricevere aiuti da voi.
Saluti e grazie per tutto il pesce.