Hey,
Ich möchte aus einem String ein Byte-Array machen und dieses dann in ein Hashset schreiben.
Jedoch schreibt die Methode add auch schon vorhandene Byte-Arrays in das Hashset.
du kannst dir ja mal ausgeben lassen was "bytes1==bytes2" ausgibt ... ich vermute FALSE ... da beide arrays nicht gleich sein dürften ...
auch wenn "abc" im stringpool gecached wird wird in "getBytes()" jeweils ein neues array erzeugt ... und da sich arrays in java eher wie objekte anstatt wie primtives verhalten dürften die beiden arrays eine unterschiedlichen hash-liefern ... was dazu führt das beide eingefügt werden ... weil beides eben "verschiedene objekte" sind ...
Nein lieber nicht. Sets sorgen schon sehr gut dafür, dass keine Duplikate vorkommen. Duplikat heißt übrigens das equals() true liefert. Und das tut es bei Arrays eben nur, wenn die identisch sind. Insofern sind Arrays ungeeignet, um sie in einem Set zu speichern. Weiche darum auf List aus.
Helfen kann dabei folgende Methde aus der Api:
Java:
Arrays.asList(...);
Und wenn Du doch mit Array-Vergleichen rumbasteln willst/musst, ist die Methode hier noch hilfreich:
Java:
Arrays.equals(a, a2);
Die macht das, was man gerne hätte, nämlich testen, ob die Elemente der Arrays gleich sind.
naja ... da "byte1==byte2" FALSE ist wird wohl Collection.contains() auch FALSE liefern ...
man könnte jetzt entsprechend des ziel-types n bissl was schreiben was durch die liste geht ... den inhalt liest und prüft ob der parameter den man adden will mit irgendeinem wert der schon drin ist gleich ist ...
für arrays gibt es "Arrays.equals(T[])" ... ansonsten einfach Object.equals(Object) ...
problem ist halt das die beiden byte-arrays nicht ein und das gleich byte-array sind sondern zwei eigenständige ... und damit halt zwei unterschiedliche objekte ... das java nicht in der lage ist hier automatisch "Arrays.equals" zu callen erstaunt mich allerdings auch etwas
Was mich irritiert ist, dass bei arrays von primitives kein irgendwie geartetes Autoboxing stattfindet wenn es in ein HashSet geschickt wird. Jedenfalls gibt das .class-File nichts davon her. Verwurschtelt die Runtime das nativ?
Was mich irritiert ist, dass bei arrays von primitives kein irgendwie geartetes Autoboxing stattfindet wenn es in ein HashSet geschickt wird. Jedenfalls gibt das .class-File nichts davon her. Verwurschtelt die Runtime das nativ?
Nein, es wird as Array als Objekt reingesteckt. Da muss nichts geboxed/geunboxed werden.
Das erkennt man ganz gut bei der generischen Definition des Sets:
Meinst du mit Source den Quellcode des JDK? Da steht ja eh nicht viel Code drinnen, weils ein Interface ist. Ich habe das jedenfalls in einem anderen Zusammenhang mal ausprobiert (nicht mit Set, sondern List, aber ist ja im Prinzip egal). Ich hab hier leider nur eine 7er-Installation, aber, wenn ich in Eclipse das Compliance-Level auf 1.5 zurück stelle, meckert er auch nicht. Ich denke also, das geht, seit es Generics gibt.
P.S. Drauf gekommen bin ich, weil es auch sowas hier gibt:
Code:
int[].class
. Und da dachte ich, alles was eine Klasse ist, kann doch bestimmt auch ein generischer Parameter werden.
Hab gerade gelesen das bei Listen die Methode contains() .equals für den Vergleich nutzt...das müsste bei zwei Inhaltlich gleichen Objekten doch true liefern oder nicht?
Stimmt. Primitive Arrays haben .class und auch .hashcode() - wobei letzterer nix bringt weil für gleiche Inhalte unterschiedliche Hashcodes erzeugt werden.
Hey,
Ich möchte aus einem String ein Byte-Array machen und dieses dann in ein Hashset schreiben.
Jedoch schreibt die Methode add auch schon vorhandene Byte-Arrays in das Hashset. z.B.
Hab gerade gelesen das bei Listen die Methode contains() .equals für den Vergleich nutzt...das müsste bei zwei Inhaltlich gleichen Objekten doch true liefern oder nicht?
Nein! Das hatten trööt und ich schon in unseren ersten Antworten geschrieben, dass equals() bei Array-Objetken eben nicht auf Elementgleichheit prüft, sondern nur true zurück gibt, wenn sie identisch sind.
Es ist tatsächlich nur dann so, dass equals auf Inhalsgleichheit prüft, wenn der Autor der Klasse es entsprechend implementiert hat. Ansonsten wird immer nur bei Identität true zurück gegeben.
P.S. Und übrigens unter der Haube prüft Set.add() auch per equals (zumindest bei den usortierten Varianten wie HashSet).
Stimmt. Primitive Arrays haben .class und auch .hashcode() - wobei letzterer nix bringt weil für gleiche Inhalte unterschiedliche Hashcodes erzeugt werden.
Ja, ich glaube, das ist Teil des Murkses, dass in der OO-Sprache Java Nicht-Objekte (also die Primitiven) vorkommen. In "echten" OO-Sprachen stellt sich das Problem ja so überhaupt nicht.
[/OT]
Hab gerade gelesen das bei Listen die Methode contains() .equals für den Vergleich nutzt...das müsste bei zwei Inhaltlich gleichen Objekten doch true liefern oder nicht?
Arrays von primitiven Datentypen werden als java.lang.Object gespeichert und das dort implementierte .equals prüft nur ob die Objektreferenzen identisch sind. In Deinem Fall werden (trotz identischem Inhalt) zwei unterschiedliche Objekte erzeugt die demnach nicht die gleiche Objektreferenz haben.
Wenn man Objekte auf inhaltliche Gleichheit prüfen möchte, muss man .equals überschreiben und das darin entsprechend Programmieren. Typischer Fall ist zb. die Klasse String wo im .equals(...) tatsächlich Zeichenweise abgeglichen wird.
Was Du machen kannst, ist einen Wrapper für Deine bytearrays zu schreiben wo das .equals(...) die arrays auf Inhalt vergleicht.
War auch eine meiner ersten Ideen. Aber dann müssten equals und hashCode in der Wrapperklasse überschrieben werden. Das ist unnötige Arbeit, wenn man mit Arrays.asList() genau so einen "Wrapper" bereits frei Haus bekommt. Und das Speichern von Arrays gilt für alle Elementtypen. Zwei nicht-identische Arrays sind nie equal auch nicht, wenn dort echte Objekte drinnen sind. Zum Test folgender Code:
Oh Gott ich will die ganze zeit antworten, komm aber nie dazu weil immer schonwieder jemand anderes geantwortet hat. Gefällt mir
Das ganze hat sich aber, denke ich, schon erledigt; Ich habe das ganze grade mal mit "gewrapten" BufferedBytes ausprobiert und das ist noch langsamer und Speicherintensiver als gleich den String als ganzes zu nehmen.
War auch eine meiner ersten Ideen. Aber dann müssten equals und hashCode in der Wrapperklasse überschrieben werden. Das ist unnötige Arbeit, wenn man mit Arrays.asList() genau so einen "Wrapper" bereits frei Haus bekommt.
Anscheinend nicht. Bei mir (Java 1.6) liefert auch Arrays.asList(...) nur eine Liste mit 1 Objekt zurück und .equals() darauf vergleicht dieses eine Objekt mit dem anderen aus der Liste via Object#equals(....).
Anscheinend nicht. Bei mir (Java 1.6) liefert auch Arrays.asList(...) nur eine Liste mit 1 Objekt zurück und .equals() darauf vergleicht dieses eine Objekt mit dem anderen aus der Liste via Object#equals(....).
Oha, da hast du mich jetzt erwischt! Ich habe das natürlich in anderen Zusamenhängen NICHT mit primitiven Arrays probiert. Der varargs-Parameter erwartet ja Objekte. Während man also einen Array von Objekten übergeben kann und die varargs-Methode das dann in die Elemente aufdröselt, tut sie das bei Primitiven-Arrays natürlich nicht, sondern nimmt das Array als einziges Objekt. Jetz weiß ich auch, was du weiter vorne mit Autoboxing meintest! Touché Herr Hohmann!
da ist man mal einen abend nicht da und hier läuft in 2h die schönste diskusion über arrays ...
ob nun arrays intern wirklich als Object gespeichert werden weis ich nicht ... aber ihre verhalten "fühlt" sich dann doch eher wie ein objekt an anstatt wie mit einem haufen primitives ...
ich weis nicht ob das nur in java so ist oder auch andere sprachen betrifft ... und ich würde gerne mal eine sprache sehen in der es KEINE primitives gibt (wie hier genannt "echt-oop") ... fällt mir halt schwer das nach zu vollziehen ...
ich denke auf die idee am besten einfach die Strings ins HashSet stecken anstatt byte-arrays sind wir hier alle sofort gekommen ... und ich wollte auch eigentlich keine diskusion über arrays , primitives und ojects anfachen ... sondern TO lediglich sagen das "byte1" eben NICHT "==" bzw "equals()" "byte2" ist ... und desshalb die interne prüfung in add() nun mal korrekterweise zwei unterschiedliche objekte siehr und beide desshalb auch ins set packt ...
mehr wollte ich eigentlich nicht sagen und damit diese diskusion hier anzetteln ... wobei ichs auch informativ finde arrays mal so auseinander zu nehmen ...
@TO
was mich jetzt nur interessieren würde für welche lösung du dich jetzt entschieden hast ...
Scala, Smalltalk, Lisp fallen mir da spontan ein. Daneben gibt es viele Nicht-OO Sprachen die ebenfalls ohne primitive Datentypen arbeiten (zb Shellsprachen, etliche Interpretersprachen wie REXX).
Das passiert nun mal, wenn man die API nicht richtig nutzt.
Da du ja Java 6 nutzt, wirst du sicherlich auch wissen, was Generics sind. [JAPI]List[/JAPI] ist generisch und [JAPI]Arrays#asList(T...)[/JAPI] auch.
Hier hätte es also einen Kompilierfehler gegeben:
ansieht.
Hilft man ihm nun auf die Sprünge, erhält man einen anderen Kompilierfehler:
Java:
List<Byte> l1 =Arrays.<Byte>asList(bytes1);// method asList in class Arrays cannot be applied to given types;// required: T[]// found: byte[]// reason: argument type byte[] does not conform to vararg element type Byte// where T is a type-variable:// T extends Object declared in method <T>asList(T...)
Man erfährt also schon beim Kompilieren, dass die API das nicht zulässt, nicht erst zur Laufzeit.
Hier hätte es also einen Kompilierfehler gegeben:[....]
Man erfährt also schon beim Kompilieren, dass die API das nicht zulässt, nicht erst zur Laufzeit.