View Full Version : [JAVA] Domanda sul cast
wingman87
31-01-2009, 00:12
Vorrei sapere come mai questo codice funziona:
public class CodaArray<T> implements Coda<T> {
T[] elementi;
int testa, lunghezza;
public CodaArray(int n) {
elementi = (T[]) new Object[n];
testa = 0;
lunghezza = 0;
}
public boolean èVuota() {
return lunghezza == 0;
}
public void accoda(T element){
if(lunghezza<elementi.length){
elementi[(testa+lunghezza)%elementi.length]=element;
lunghezza++;
}
}
public T primo(){
if(lunghezza==0) return null;
return elementi[testa];
}
public T estraiPrimo(){
if(lunghezza==0) return null;
T el=elementi[testa];
testa++;
if(testa==elementi.length)
testa=0;
lunghezza--;
return el;
}
public static void main(String[] args){
Coda<Integer> q=new CodaArray<Integer>(10);
q.accoda(2);
q.accoda(12);
System.out.println(q.estraiPrimo()+" "+q.estraiPrimo());
}
}
In particolare non capisco come può funzionare la linea che ho evidenziato in rosso. D'altra parte questo non funziona:
public class Prova{
public static void main(String[] args){
String[] a=(String[])new Object[10];
}
}
Qualcuno me lo può spiegare?
E magari tanto che ci siete mi spiegate anche quando viene visualizzato il seguente warning?
warning: [unchecked] unchecked cast
Perché ad esempio nel cast evidenziato sopra me lo segnala, in altri no, cosa cambia tra quello e gli altri?
Grazie!
wingman87
01-02-2009, 02:10
Uppete!
In particolare non capisco come può funzionare la linea che ho evidenziato in rosso. be', secondo te che errore dovrebbe dare? io la trovo perfettamente regolare, un array di Object castato ad un array di T (comunque considera che T estende per forza Object poiché nei parametri del generic hai specificato un nome e non un punto interrogativo).
D'altra parte questo non funziona:
public class Prova{
public static void main(String[] args){
String[] a=(String[])new Object[10];
}
} uh? che errore da...?
E magari tanto che ci siete mi spiegate anche quando viene visualizzato il seguente warning?
warning: [unchecked] unchecked cast questo a me lo da' quando cerco di castare verso un generic non parametrizzato, ad esempio ArrayList (non ArrayList<...>).
wingman87
01-02-2009, 20:10
be', secondo te che errore dovrebbe dare? io la trovo perfettamente regolare, un array di Object castato ad un array di T (comunque considera che T estende per forza Object poiché nei parametri del generic hai specificato un nome e non un punto interrogativo).
Innanzitutto grazie per la risposta.
Qui la cosa che non capisco è come è possibile fare il cast da un oggetto di tipo meno particolare ad uno più particolare. Io lo vedo (evidentemente sbaglio) come se facessi
String s=(String)new Object();
E questo in esecuzione infatti dà errore "java.lang.ClassCastException"
uh? che errore da...?
Lo stesso: java.lang.ClassCastException
questo a me lo da' quando cerco di castare verso un generic non parametrizzato, ad esempio ArrayList (non ArrayList<...>).
E riguardo al fatto che me lo dà anche alla riga che ho evidenziato? Qual è il motivo?
Innanzitutto grazie per la risposta.
Qui la cosa che non capisco è come è possibile fare il cast da un oggetto di tipo meno particolare ad uno più particolare. e secondo te a che serve il cast allora? :D
il cast serve in casi come questi:
Object actuallyAString = "hello, world";
String string = (String)actuallyAString;
mi sembra perfettamente regolare.
Io lo vedo (evidentemente sbaglio) come se facessi
String s=(String)new Object();
E questo in esecuzione infatti dà errore "java.lang.ClassCastException" questo si, perché l'oggetto effettivamente castato non é String ma Object; ma nel caso dell'array non vedo il problema visto che gli elementi di un array Object[] possono tranquillamente essere tutti quanti di tipo T.
Lo stesso: java.lang.ClassCastException al momento, vista l'ora, non mi va di provare :D
peró io non capisco quale sia, nel tuo esempio, l'oggetto non castabile: non hai assegnato nessun elemento nell'array.
E riguardo al fatto che me lo dà anche alla riga che ho evidenziato? Qual è il motivo? probabilmente proprio per avvisarti che un array di Object puó potenzialmente contenere oggetti di tipo diverso da T, incluso Object; quindi castando ad array di T potresti avere delle ClassCastException per alcuni degli elementi. di fatto non cosa accada in una simile situazione, la ClassCastException l'ho ipotizzata; questo sarebbe un esperimento interessante da fare:
class Generic<T>
{
public Generic(T t)
{
Object[] objectArray = new Object[2];
objectArray[0] = t;
objectArray[1] = new Object();
T[] array = (T[])objectArray;
System.out.println(array[0].toString());
System.out.println(array[1].toString());
}
}
.
.
.
new Generic<String>("ciao");
wingman87
02-02-2009, 00:25
e secondo te a che serve il cast allora? :D
Forse mi sono spiegato male: non mi sono chiesto come è possibile fare un cast da un tipo meno particolare a uno più particolare, ma come è possibile fare un cast da un oggetto di tipo meno particolare a uno più particolare. L'oggetto in questo caso è un array di Object e si vuole fare un cast a qualcosa di più particolare, ossia un array di T.
il cast serve in casi come questi:
Object actuallyAString = "hello, world";
String string = (String)actuallyAString;
mi sembra perfettamente regolare.
In questo caso l'oggetto è di tipo String e non stai facendo un cast a un tipo più particolare, lo stai castando a String.
questo si, perché l'oggetto effettivamente castato non é String ma Object; ma nel caso dell'array non vedo il problema visto che gli elementi di un array Object[] possono tranquillamente essere tutti quanti di tipo T.
E' vero ma non stai dicendo il contrario di quello che è scritto nel codice?
Nel codice sto assumendo che in un array T[] gli oggetti possono tranquillamente essere degli Object. O no? :mbe:
al momento, vista l'ora, non mi va di provare :D
peró io non capisco quale sia, nel tuo esempio, l'oggetto non castabile: non hai assegnato nessun elemento nell'array.
Penso sia il nocciolo della questione. Non capisco perché quel codice non va mentre quello generico sì... Secondo me non dovrebbe funzionare nessuno dei due.
probabilmente proprio per avvisarti che un array di Object puó potenzialmente contenere oggetti di tipo diverso da T, incluso Object; quindi castando ad array di T potresti avere delle ClassCastException per alcuni degli elementi.
Ma esplicitando il cast io non dovrei sollevare il compilatore dall'onere di avvertirmi che sto facendo delle operazioni non sicure? Cioè, a sto punto tutti i cast non sono sicuri e dovrei ricevere un warning per ognuno di essi.. Cos'ha di speciale quel cast che un cast come questo:
String s=(String)new Object();
non ha? (Oltretutto questo solleva l'eccezione a runtime, ovviamente)
^TiGeRShArK^
02-02-2009, 10:58
è tutto assolutamente normale.
Quando istanzi un array di object e poi lo casti a string[] al compile time non hai ovviamente alcun errore, ma al runtime, quando la VM tenta di utilizzare l'array di object come fosse un array di string ti va in eccezione perchè i due tipi sono diversi.
Col generic ti funziona invece perchè stai facendo il contrario, ovvero stai castando un qualsiasi oggeto (che per definizione estende da object) ad object, operazione perfettamente lecita.
Se fai la stessa cosa nel tuo codice fuori dalla classe generic ovviamente ti funziona dato che:
Object[] o = (Object[])new String[10];
è un'operazione assolutamente legale.
Forse mi sono spiegato male: non mi sono chiesto come è possibile fare un cast da un tipo meno particolare a uno più particolare, ma come è possibile fare un cast da un oggetto di tipo meno particolare a uno più particolare. hai ragione, ieri sera non capivo niente, era tardi :p
comunque: convertire da un oggetto meno particolare ad uno piu particolare é possibile proprio grazie al cast esplicito (esempio: é possibile interpretare un riferimento di tipo Object come se fosse di tipo String se effettivamente esso si riferisce ad un oggetto String; altrimenti ClassCastException).
invece: convertire da un oggetto piu particolare ad uno meno particolare ovviamente é possibile in maniera del tutto naturale (esempio: un riferimento di tipo String puó essere assegnato ad uno di tipo Object con cast implicito).
chiarito questo andiamo avanti.
L'oggetto in questo caso è un array di Object e si vuole fare un cast a qualcosa di più particolare, ossia un array di T. un array di Object equivale a tanti riferimenti di tipo Object; questi riferimenti non é detto che contengano oggetti di tipo Object, potrebbero anche contenere oggetti di un qualunque tipo che eredita Object, come ad esempio T. ma potrebbero anche non farlo, da cui il warning. il warning ti dice che se tu casti tutti quei riferimenti di tipo Object a riferimenti di tipo T, a runtime qualcuno di quei riferimenti potrebbe causare una ClassCastException (non so di preciso in che momento) perché potrebbe di fatto contenere un Object anziché un T (per esempio).
In questo caso l'oggetto è di tipo String e non stai facendo un cast a un tipo più particolare, lo stai castando a String. l'oggetto si, ma il riferimento no: quello era di tipo Object, e la seconda istruzione dell'esempio non puó sapere che esso in realtá contiene un oggetto String piuttosto che un Object o qualcos'altro che erediti Object; semplicemente ci si fida del programmatore, il cast é forzato. se poi il riferimento non conteneva una String allora ClassCastException a runtime.
Nel codice sto assumendo che in un array T[] gli oggetti possono tranquillamente essere degli Object. O no? :mbe: no: quello non é un array di T; viene solo visto come array di T ma di fatto é un array di Object, e come tale puó contenere tanto degli Object quanto dei T. non ho capito dove vuoi arrivare.
Penso sia il nocciolo della questione. Non capisco perché quel codice non va mentre quello generico sì... Secondo me non dovrebbe funzionare nessuno dei due. tigershark ha chiarito la questione; scusa se non me ne sono accorto ma ieri sera ero fuso :)
Ma esplicitando il cast io non dovrei sollevare il compilatore dall'onere di avvertirmi che sto facendo delle operazioni non sicure? Cioè, a sto punto tutti i cast non sono sicuri e dovrei ricevere un warning per ognuno di essi.. vero, ma devi considerare che nel caso di un array c'é molta piu possibilitá di errore perché un riferimento é un riferimento solo, mentre un array sono N riferimenti :D
wingman87
02-02-2009, 13:57
Inizio a capire ma c'è ancora qualcosa che non mi è chiaro... scusatemi.
è tutto assolutamente normale.
Quando istanzi un array di object e poi lo casti a string[] al compile time non hai ovviamente alcun errore, ma al runtime, quando la VM tenta di utilizzare l'array di object come fosse un array di string ti va in eccezione perchè i due tipi sono diversi.
Col generic ti funziona invece perchè stai facendo il contrario, ovvero stai castando un qualsiasi oggeto (che per definizione estende da object) ad object, operazione perfettamente lecita.
Se fai la stessa cosa nel tuo codice fuori dalla classe generic ovviamente ti funziona dato che:
Object[] o = (Object[])new String[10];
è un'operazione assolutamente legale.
Ma nel generic non mi sembra che sto facendo questo, sto facendo:
elementi = (T[]) new Object[n];
Cioè un cast da array di Object a T[].
un array di Object equivale a tanti riferimenti di tipo Object; questi riferimenti non é detto che contengano oggetti di tipo Object, potrebbero anche contenere oggetti di un qualunque tipo che eredita Object, come ad esempio T. ma potrebbero anche non farlo, da cui il warning. il warning ti dice che se tu casti tutti quei riferimenti di tipo Object a riferimenti di tipo T, a runtime qualcuno di quei riferimenti potrebbe causare una ClassCastException (non so di preciso in che momento) perché potrebbe di fatto contenere un Object anziché un T (per esempio).
Questo mi sembra molto ragionevole ma allora dovrebbe funzionare anche il cast
String[] a=(String[])new Object[10];
perché al momento del cast l'array non contiene ancora nulla
no: quello non é un array di T; viene solo visto come array di T ma di fatto é un array di Object, e come tale puó contenere tanto degli Object quanto dei T. non ho capito dove vuoi arrivare.
Questo ora mi è chiaro, grazie.
vero, ma devi considerare che nel caso di un array c'é molta piu possibilitá di errore perché un riferimento é un riferimento solo, mentre un array sono N riferimenti :D
Anche questo mi sembra ragionevole. Grazie.
^TiGeRShArK^
02-02-2009, 16:49
vero, ho letto male :fagiano:
cmq nel generic te lo fa fare perchè a quel livello non sa di che tipo è T.
Potrebbe benissimo essere un Object, e in quel caso è perfettamente legale.
Se però usi come tipo String allora al runtime ti darà un errore.
Ergo, usare dei cast espliciti in quel modo all'interno di una classe generic è altamente sconsigliato dato che rompi la type safety al compile time, non per niente ti viene comunicato un warning ;)
wingman87
02-02-2009, 16:53
Eppure a runtime funziona con il main che ho scritto, cioè dove uso Integer (se avessi usato String sarebbe stato lo stesso). Ti passo anche l'interfaccia così puoi provare.
public interface Coda<T> {
public boolean èVuota();
public void accoda(T element);
public T primo();
public T estraiPrimo();
}
^TiGeRShArK^
02-02-2009, 17:26
allega tutto il progetto così gli do un occhiata ;)
wingman87
02-02-2009, 17:29
Praticamente sono solo i due file che ho postato, l'interfaccia e l'implementazione. Ti ho allegato anche i file class, nel caso non avessi il compilatore sotto mano. Grazie
banryu79
02-02-2009, 17:36
Una piccolezza:
public interface Coda<T> {
public boolean èVuota();
public void accoda(T element);
public T primo();
public T estraiPrimo();
}
rinomina quel membro in: vuota.
Non usare mai lettere accentate nel codice sorgente, aggiungo neanche nei commenti.
wingman87
02-02-2009, 17:39
Che tipo di problemi comporta? Comunque in genere scrivo tutto in inglese ma questo è un esempio che ho preso dalle slide di un mio professore.
banryu79
02-02-2009, 17:40
...è un esempio che ho preso dalle slide di un mio professore.
Ah, benone :D
^TiGeRShArK^
02-02-2009, 17:58
ok provato.
Mi sa che il compilatore si accorge che in realtà gli viene passato un tipo integer e aggiorna automaticamente l'array trasformandolo da object ad integer evitando l'errore al run-time..
è l'unica spiegazione che mi viene in mente....:boh:
Che tipo di problemi comporta? impone restrizioni sul charset con cui deve essere salvato il file: non tutti i charset supportano i caratteri accentati, cosi come altri caratteri. in generale sarebbe bene usare sempre e solo i caratteri del set ASCII non esteso: lettere minuscole e maiuscole, numeri, punteggiature, simboli comuni.
banryu79
02-02-2009, 18:19
ok provato.
Mi sa che il compilatore si accorge che in realtà gli viene passato un tipo integer e aggiorna automaticamente l'array trasformandolo da object ad integer evitando l'errore al run-time..
è l'unica spiegazione che mi viene in mente....:boh:
Auto-boxing "esteso" :sofico:
wingman87
02-02-2009, 18:38
ok provato.
Mi sa che il compilatore si accorge che in realtà gli viene passato un tipo integer e aggiorna automaticamente l'array trasformandolo da object ad integer evitando l'errore al run-time..
è l'unica spiegazione che mi viene in mente....:boh:
Mi sembra artificioso però non ho idea di come potrebbe essere altrimenti...
Tuttavia quello che diceva fero86 non mi sembrava sbagliato, mi riferisco a
un array di Object equivale a tanti riferimenti di tipo Object; questi riferimenti non é detto che contengano oggetti di tipo Object, potrebbero anche contenere oggetti di un qualunque tipo che eredita Object, come ad esempio T. ma potrebbero anche non farlo, da cui il warning. il warning ti dice che se tu casti tutti quei riferimenti di tipo Object a riferimenti di tipo T, a runtime qualcuno di quei riferimenti potrebbe causare una ClassCastException (non so di preciso in che momento) perché potrebbe di fatto contenere un Object anziché un T (per esempio).
Cioè, dovrebbe essere possibile fare
String[] a=(String[])new Object[10]; //E in realtà qui da errore
ma non
Object[] oA={new Object()};
String[] sA=(String[])oA;
String s=sA[0]; //Qui dovrebbe dare errore
impone restrizioni sul charset con cui deve essere salvato il file: non tutti i charset supportano i caratteri accentati, cosi come altri caratteri. in generale sarebbe bene usare sempre e solo i caratteri del set ASCII non esteso: lettere minuscole e maiuscole, numeri, punteggiature, simboli comuni.
Non ci avevo pensato, grazie.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.