/ Forside / Teknologi / Udvikling / Java / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
Java
#NavnPoint
molokyle 3688
Klaudi 855
strarup 740
Forvirret 660
gøgeungen 500
Teil 373
Stouenberg 360
vnc 360
pmbruun 341
10  mccracken 320
Casting af et objekt array
Fra : Janus


Dato : 13-12-05 04:47

Sigmigligeengang,


kan man ikke caste et Object array til dets egentlige type? Og hvis nej,
hvorfor ikke?


Foo[] fArray = (Foo[])myVector.toArray();


-resulterer i en java.lang.ClassCastException



På forhånd tak,
Janus

 
 
Thorbjørn Ravn Ander~ (13-12-2005)
Kommentar
Fra : Thorbjørn Ravn Ander~


Dato : 13-12-05 05:44

Janus <nospam@nomail.com> writes:

> kan man ikke caste et Object array til dets egentlige type? Og hvis
> nej, hvorfor ikke?
>
>
> Foo[] fArray = (Foo[])myVector.toArray();

Fordi den returnerede Object[] ikke kan castes til en Foo[].

Du skal fortælle toArray med et argument hvilken type den skal
generere. SÅ virker det.
--
Thorbjørn Ravn Andersen
http://unixsnedkeren.dk/ravn/

Lasse Reichstein Nie~ (10-01-2006)
Kommentar
Fra : Lasse Reichstein Nie~


Dato : 10-01-06 08:42

Mads Bahrt <mads_bahrt@hotmail.com> writes:

> Hvis man kigger i Java 1.4.2 javadoc'en for Collection interfacet (
> http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html )
> vil man se at det interface eksisterede inden generics, så det er
> derfor du selv er nødt til at oplyse typen.

Det er ikke kun fordi interfacet er ældre. Du ville heller ikke
kunne gøre det i et nyt interface, fordi generics er et compile-time
typesystem. På runtime, hvor arrayet skal instantieres, findes
typeinformationen slet ikke, så det bedste man kan gøre er at lave
et Object[], med mindre brugeren fortæller noget andet.

/L
--
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Henrik Stidsen (13-12-2005)
Kommentar
Fra : Henrik Stidsen


Dato : 13-12-05 05:59

Janus wrote on 13-12-2005 :
> Foo[] fArray = (Foo[])myVector.toArray()

Du skal gøre sådan her:

   Vector foo = new Vector();
   foo.add("bla bla bla");
   foo.add("alb alb alb");

   String[] bar = new String[foo.size()];
   foo.toArray(bar);

Det er godt nok med en ArrayList og ikke en Vector, men de virker jo
stort set på samme måde...

--
Henrik Stidsen - http://henrikstidsen.dk/
This is not an automated signature. I type this in to the bottom of
every message.



Mads (22-12-2005)
Kommentar
Fra : Mads


Dato : 22-12-05 10:52

Henrik Stidsen wrote:
> Janus wrote on 13-12-2005 :
>
>> Foo[] fArray = (Foo[])myVector.toArray()
>
>
> Du skal gøre sådan her:
>
> Vector foo = new Vector();
> foo.add("bla bla bla");
> foo.add("alb alb alb");
>
> String[] bar = new String[foo.size()];
> foo.toArray(bar);
>
> Det er godt nok med en ArrayList og ikke en Vector, men de virker jo
> stort set på samme måde...
>
Var det ikke mere sikkert at skrive:

String[] bar = foo.toArray(new String[foo.size()]);

Hvis man nu har flere tråde der tilgår foo, så er der vel mulighed for
følgende race condition:
Tråd 1: String[] bar = new String[foo.size()];
Tråd 2: foo.add("lba lba lba");
Tråd 1: foo.toArray(bar);

toArray vil indse at array'et bar peger på er for kort og derfor
allokere et nyt og returnere en pointer til dette. Men denne pointer
bliver smidt på gulvet.

På den anden side, så har jeg ikke lige tjekket om Vector.toArray er
thread safe.

Venlig hilsen
Mads

Johnnie Hougaard Nie~ (22-12-2005)
Kommentar
Fra : Johnnie Hougaard Nie~


Dato : 22-12-05 11:19

Mads wrote:
> Hvis man nu har flere tråde der tilgår foo, så er der vel mulighed for
> følgende race condition:

Nej - foo er jo en lokal variable for metoden (ikke en instans
variabel).

> På den anden side, så har jeg ikke lige tjekket om Vector.toArray er
> thread safe.

Metoden er synchronized. Men det ville eksemplet ikke blive det mindste
threadsafe af, selv om det var en instans variabel. En af grundene til
at lade være med at bruge de forældede klasser som Vector er netop at de
er synchronized. Det er ret sjældent at det er nok til at gøre kodning
omkring disse threadsafe; og derfor er det spild af tid.

Eksemplet fra denne tråd illustrerer dette. Hvis foo var en instans
variabel, kunne det være nødvendigt med synchronized (eller mere moderne
concurrency håndtering) omrkring passende sektioner af koden.
Det ville med stor sandsynlig være meningsløst at forsøge at lade 2 x
Vector.toArray (i hver sin tråd) maltraktere samme array uden at den ene
vil få noget vrøvl ud af hvad den anden gjorde.

/Johnnie

Arne Vajhøj (22-12-2005)
Kommentar
Fra : Arne Vajhøj


Dato : 22-12-05 12:03

Mads wrote:
> Henrik Stidsen wrote:
>> Du skal gøre sådan her:
>>
>> Vector foo = new Vector();
>> foo.add("bla bla bla");
>> foo.add("alb alb alb");
>>
>> String[] bar = new String[foo.size()];
>> foo.toArray(bar);

> Var det ikke mere sikkert at skrive:
>
> String[] bar = foo.toArray(new String[foo.size()]);
>
> Hvis man nu har flere tråde der tilgår foo, så er der vel mulighed for
> følgende race condition:
> Tråd 1: String[] bar = new String[foo.size()];
> Tråd 2: foo.add("lba lba lba");
> Tråd 1: foo.toArray(bar);
>
> toArray vil indse at array'et bar peger på er for kort og derfor
> allokere et nyt og returnere en pointer til dette. Men denne pointer
> bliver smidt på gulvet.
>
> På den anden side, så har jeg ikke lige tjekket om Vector.toArray er
> thread safe.

Hvis vi nu lige ignorerer at foo ligner en lokal variabel og
antager at det er en instans variabel som kan tilgåes af
flere tråde.

String[] bar = foo.toArray(new String[foo.size()]);

er heller ikke thread safe.

Tråd 1: new String[foo.size()];
Tråd 2: foo.add("lba lba lba");
Tråd 1: foo.toArray

Efter min bedste vurdering er det endda samme sandsynelighed
for problemer, da jeg tror at der vil blive udført præcis det
samme for de to stykker kode.

Vector toArray er thread safe (synchronized) men det er ligegyldigt.

Der er nemlig brug for at synkronisere på et højere niveau
mellem kaldene til size og toArray.

Arne


Søren Berg Glasius (22-12-2005)
Kommentar
Fra : Søren Berg Glasius


Dato : 22-12-05 15:43

Arne Vajhøj wrote:

> String[] bar = foo.toArray(new String[foo.size()]);
>
> er heller ikke thread safe.
>
> Tråd 1: new String[foo.size()];
> Tråd 2: foo.add("lba lba lba");
> Tråd 1: foo.toArray
>

Hvad med blot at benytte

String[] bar = (String[])foo.toArray(new String[0]);

I følge API'et returnere toArray et nyt array, hvis foo.size() ikke
passer ind i størrelsen på array'et som parses ind i funktionen. Og med
størrelsen '0' kan man ikke sige, at der er meget plads i array'et.

MVH
Søren Berg Glasius

Arne Vajhøj (22-12-2005)
Kommentar
Fra : Arne Vajhøj


Dato : 22-12-05 16:19

Søren Berg Glasius wrote:
> Arne Vajhøj wrote:
> Hvad med blot at benytte
>
> String[] bar = (String[])foo.toArray(new String[0]);
>
> I følge API'et returnere toArray et nyt array, hvis foo.size() ikke
> passer ind i størrelsen på array'et som parses ind i funktionen. Og med
> størrelsen '0' kan man ikke sige, at der er meget plads i array'et.

Det gør man ofte.

Og da size ikke bliver kaldt så forsvinder alle thread problemerne.

Arne

Mads (01-01-2006)
Kommentar
Fra : Mads


Dato : 01-01-06 16:02

Arne Vajhøj wrote:
>
> Hvis vi nu lige ignorerer at foo ligner en lokal variabel og
> antager at det er en instans variabel som kan tilgåes af
> flere tråde.
Jaja... det er jo ligesom implicit når vi snakker concurrency.

>
> String[] bar = foo.toArray(new String[foo.size()]);
>
> er heller ikke thread safe.
>
> Tråd 1: new String[foo.size()];
> Tråd 2: foo.add("lba lba lba");
> Tråd 1: foo.toArray
>
> Efter min bedste vurdering er det endda samme sandsynelighed
> for problemer, da jeg tror at der vil blive udført præcis det
> samme for de to stykker kode.
>
Ja men foo.toArray vil så bare allokere et nyt array og returnere en
pointer til dette som så vil blive gemt i bar.
Min pointe er jo netop at vi skal bruge retur værdien fra toArray(..).

Det array vi får allokeret med "new String[foo.size()]" vil så bare
blive garbage collected. Forhåbentligt rimelig hurtigt da det må antages
at ligge i 1. generation.

Venlig hilsen
Mads

Arne Vajhøj (01-01-2006)
Kommentar
Fra : Arne Vajhøj


Dato : 01-01-06 17:23

Mads wrote:
>> String[] bar = foo.toArray(new String[foo.size()]);
>>
>> er heller ikke thread safe.
>>
>> Tråd 1: new String[foo.size()];
>> Tråd 2: foo.add("lba lba lba");
>> Tråd 1: foo.toArray
>>
>> Efter min bedste vurdering er det endda samme sandsynelighed
>> for problemer, da jeg tror at der vil blive udført præcis det
>> samme for de to stykker kode.
>>
> Ja men foo.toArray vil så bare allokere et nyt array og returnere en
> pointer til dette som så vil blive gemt i bar.
> Min pointe er jo netop at vi skal bruge retur værdien fra toArray(..).
>
> Det array vi får allokeret med "new String[foo.size()]" vil så bare
> blive garbage collected. Forhåbentligt rimelig hurtigt da det må antages
> at ligge i 1. generation.

Ved add.

Ved remove vil du få et array padded med null's.

Enten syncher man mellem size og toArray eller så
kalder man med et array med dimension 0, som en anden
postede.

Arne

Bjarke Walling Peter~ (08-01-2006)
Kommentar
Fra : Bjarke Walling Peter~


Dato : 08-01-06 12:20

Thorbjørn Ravn Andersen skrev:
> Du skal fortælle toArray med et argument hvilken type den skal
> generere. SÅ virker det.

I den forbindelse har jeg et spørgsmål. Det er godt nok sjældent jeg
bruger det indbyggede array direkte, normalt benytter jeg abstraktioner
som arraylist e.lign., men hvis jeg nu alligevel skulle komme ud for at
konvertere til et simpelt array:

// Jeg fortæller her compileren at min liste indeholder Foo objekter:
List<Foo> myList = new ArrayList<Foo>();
// Hvorfor skal jeg til at fortælle den det igen her? Efter min mening
// burde man kunne nøjes med myList.toArray(), når man nu har
// generiske typer i Java 1.5. Er det ikke en fejl fra Suns side?
Foo[] myArray = myList.toArray(new Foo[0]);

Kan nogen forklare mig hvorfor de (Sun vel sagtens) har lavet det på
den måde?

Mvh.
Bjarke W.


Arne Vajhøj (09-01-2006)
Kommentar
Fra : Arne Vajhøj


Dato : 09-01-06 17:54

Bjarke Walling Petersen wrote:
> I den forbindelse har jeg et spørgsmål. Det er godt nok sjældent jeg
> bruger det indbyggede array direkte, normalt benytter jeg abstraktioner
> som arraylist e.lign., men hvis jeg nu alligevel skulle komme ud for at
> konvertere til et simpelt array:
>
> // Jeg fortæller her compileren at min liste indeholder Foo objekter:
> List<Foo> myList = new ArrayList<Foo>();
> // Hvorfor skal jeg til at fortælle den det igen her? Efter min mening
> // burde man kunne nøjes med myList.toArray(), når man nu har
> // generiske typer i Java 1.5. Er det ikke en fejl fra Suns side?
> Foo[] myArray = myList.toArray(new Foo[0]);
>
> Kan nogen forklare mig hvorfor de (Sun vel sagtens) har lavet det på
> den måde?

List<Foo> myList = new ArrayList<Foo>();
Foo[] myArray = myList.toArray(new Foo[0]);

virker !

Arne


Arne Vajhøj (09-01-2006)
Kommentar
Fra : Arne Vajhøj


Dato : 09-01-06 17:58

Arne Vajhøj wrote:
> Bjarke Walling Petersen wrote:
>> I den forbindelse har jeg et spørgsmål. Det er godt nok sjældent jeg
>> bruger det indbyggede array direkte, normalt benytter jeg abstraktioner
>> som arraylist e.lign., men hvis jeg nu alligevel skulle komme ud for at
>> konvertere til et simpelt array:
>>
>> // Jeg fortæller her compileren at min liste indeholder Foo objekter:
>> List<Foo> myList = new ArrayList<Foo>();
>> // Hvorfor skal jeg til at fortælle den det igen her? Efter min mening
>> // burde man kunne nøjes med myList.toArray(), når man nu har
>> // generiske typer i Java 1.5. Er det ikke en fejl fra Suns side?
>> Foo[] myArray = myList.toArray(new Foo[0]);
>>
>> Kan nogen forklare mig hvorfor de (Sun vel sagtens) har lavet det på
>> den måde?
>
> List<Foo> myList = new ArrayList<Foo>();
> Foo[] myArray = myList.toArray(new Foo[0]);
>
> virker !

Nu nu fik jeg læst det rigtigt.

List<Foo> myList = new ArrayList<Foo>();
Foo[] myArray = myList.toArray();

virker ikke.

Fordi at:
- når koden i toArray() compiles ved den ikke hvad den skal allokere
- man ikke kan caste fra Object[] til String[]

Arne

Mads Bahrt (09-01-2006)
Kommentar
Fra : Mads Bahrt


Dato : 09-01-06 19:40

Bjarke Walling Petersen wrote:
> // Jeg fortæller her compileren at min liste indeholder Foo objekter:
> List<Foo> myList = new ArrayList<Foo>();
> // Hvorfor skal jeg til at fortælle den det igen her? Efter min mening
> // burde man kunne nøjes med myList.toArray(), når man nu har
> // generiske typer i Java 1.5. Er det ikke en fejl fra Suns side?
> Foo[] myArray = myList.toArray(new Foo[0]);
>
> Kan nogen forklare mig hvorfor de (Sun vel sagtens) har lavet det på
> den måde?

Hvis man kigger i Java 1.4.2 javadoc'en for Collection interfacet (
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html ) vil
man se at det interface eksisterede inden generics, så det er derfor du
selv er nødt til at oplyse typen. Det er også derfor at toArray uden
parametre fortsat kun returnerer et Object[], da man ellers ville miste
bagudkompatibiliteten med eksisterende kildekode. Men jeg kunne også
godt have tænkt mig at der udover de to toArray metoder blev leveret en
pænere løsning til at returnere et array af den type som jeg oplyste ved
instantieringen.

MVH

Mads

Bjarke Walling Peter~ (10-01-2006)
Kommentar
Fra : Bjarke Walling Peter~


Dato : 10-01-06 17:42

Lasse Reichstein Nielsen skrev:
> Mads Bahrt <mads_bahrt@hotmail.com> writes:
> > Hvis man kigger i Java 1.4.2 javadoc'en for Collection interfacet (
> > http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html )
> > vil man se at det interface eksisterede inden generics, så det er
> > derfor du selv er nødt til at oplyse typen.
>
> Det er ikke kun fordi interfacet er ældre. Du ville heller ikke
> kunne gøre det i et nyt interface, fordi generics er et compile-time
> typesystem. På runtime, hvor arrayet skal instantieres, findes
> typeinformationen slet ikke, så det bedste man kan gøre er at lave
> et Object[], med mindre brugeren fortæller noget andet.

Jeg var i dag til et foredrag med Peter von der Ahe om features i Java
5.0 - ret spaendende i oevrigt. I pausen snakkede jeg lidt med ham om
generics og bl.a. ovenstaaende. Et andet eksempel af lignende karakter,
er hvis man selv vil implementere en generisk data type. F.eks.:

public class Stack<E> {
private static final int CAPACITY = 10;
private E[] = new E[CAPACITY];
... metoder ...
}

Man kan maaske undres, men ovenstaaende er ikke muligt - man skal i
stedet bruge Object og benytte casts de rette steder. Grunden i oevrigt
ret logisk, og den samme som Lasse skriver ovenfor. Pga. type erasing
kan typen ikke bestemmes runtime. Der bliver gemt meta-information om
generics i class-filen til compileren, men virtual machine benytter sig
ikke af denne information. Den stoerste grund at man skal vaere
bagudkompatibel med 1.4.2. Peter von der Ahe havde i oevrigt den
holdning, at generics er indfoert for applikations programmoerernes
skyld - ikke for de tekniske, der implementerer algoritmer,
datastrukturer o.lign., hvilket nok er grunden til at man ikke har
lavet denne runtime feature. Der vil heller ik vaere udsigt til at den
kommer i 6.0 - maaske i 7.0, hvor der muligvis kommer en ny byte-code
struktur, men ikke noget han kan sige helt fast. Som han siger:
Generics hjaelper allerede den stoerste del af vejen med dumme
programmoerfejl i den form de er i nu.

I oevrigt vildt hvad Java 5.0 er i stand til med ikke-synkroniserede og
alligevel thread-safe datastrukturer!

Mvh.
Bjarke W.


Søg
Reklame
Statistik
Spørgsmål : 177579
Tips : 31968
Nyheder : 719565
Indlæg : 6409073
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste