Moin,
ohne jetzt mal die Hintergrund-Story zu erzählen wie es zu diesem Thread gekommen ist mal die Frage : machen unsigned int/long in Java überhaupt sinn ?
Konkret geht es um folgendes :
Bei meiner Suche nach Informationen über AES bin ich auf einen Hinweis gestoßen das die “Bit-Breite” von Datentypen abhängig vom System und der Sprache ist. Darauf kam mir Frage : wie sieht es eigentlich bei Java aus ? Nun, zum Glück gibt es dazu recht eindeutige Auskünfte welche primitiven Typen es gibt, wie “breit” sie sind und ob sie signed oder unsigned sind. Da ich dies in der aktuellen v8 nachgeschlagen habe bin ich dort über den Punkt gestolpert : “ab Java8 oder höher werden auch unsigned int und long unterstützt”. Als wietere Erklärung wird angegeben das man zur korrekten arithmetischen Verarbeitung die Wraper-Klassen und die neuen unsigned-Methoden nutzen muss.
Was mir jetzt nur komisch vorkommt : Java wurde von Beginn an so designed das es nur signed Datentypen gibt, mit Ausnahme von char. Macht es nun sinn daran was zu ändern und in ein änliches Chaos wie C zu fallen oder ist das eine dieser Randnotizen die man zwar mal gehört hat (haben sollte) aber getroßt in die staubige Ecke donnern kann ?
Gibt es überhaupt sinnvolle Anwendungsfälle (speziell bezogen auf Java) in denen ein unsigned int/long gerechtfertigt wäre ? Vor allem dann wenn man schon laut DOC nur mit den Wraper-Klassen arbeiten kann/muss. Da ergibt sich für mich kein Unterschied zu BigInteger.
Ich hab zwar mal in den Source geguckt und da wird wohl etwas weniger “Bit-Rumgeschubse” betrieben als bei BigInteger, aber wirklich nachvollziehen kann ichs nicht.
Mich würden dazu einfach mal so eure Gedanken interessieren … brauchbar oder doch eher daneben ?
Also brauchbar find ich das schon. Nur ich denke mal, dass sich inzwischen jeder, der schon länger Java programmiert, schlicht an vorzeichenbehaftete Datentypen gewöhnt hat. Noch brauchbarer wäre es allerdings, wenn diese Typen auch tatsächlich als Primitive oder als mutable Wrapper eingeführt worden wären, denn meistens fehlte es diesbezüglich ja an Zählwerken im positiven Bereich. Soweit ich das verstanden habe, gibt es in Java 8 diese Typen auch nach wie vor nicht wirklich, sondern es wurden vielmehr Konversions-Methoden in die Wrapper Short, Integer und Long eingefügt, also bleibt alles prinzipiell eh wie gehabt.
Angesehen habe ich mir das noch nicht im Detail. Es ist wohl nichts, was jeder jeden Tag verwenden wird. Es gibt aber immer mal wieder “spezielle” Fälle, wo unsigned praktisch sein könnte (wenn man etwa irgendein Serialisierungsprotokoll implementiert, oder einen Reader für irgendein bestimmtes Dateiformat, oder irgendwas, was mit Netzwertkomunikation zu tun hat (dass nun “Byte” keine dieser Hilfsmethoden enthält, ist so gesehen unglücklich…). Der wichtige Unterschied zu BigInteger ist aber, dass die größe dieser Typen nach wie vor bekannt (und vor allem: begrenzt!) ist. Theoretisch kann der JIT solche Operationen dann auf die passenden Maschineninstruktionen abbilden, was bei BigInteger nicht möglich wäre.
Also was Dateitypen angeht… Ausser Sounddateien sind mir noch keine weiteren begegnet, wo man unbedingt auf diese Datentypen angewiesen ist. Und wenn schon, die Reader bzw. Streams sind ja bereits durchweg auf Typerweiterungen ausgelegt, so wird z.B. für unsignedInt ein long zurückgegeben. Das einzige, was dort im Zweifelsfalle fehlt, wäre unsignedLong, war aber bisher auch noch nicht notwendig.
Wenn man so will existieren ausser für Arrays nichtmal primitive Datentypen mit geringerer Bitbreite als 32, denn außer für Klassen- und Zeichenkettenreferenzen werden dort mindestens 4 Byte pro Konstante abgelegt, selbst wenn im Quellcode boolean, byte, short und/oder char verwendet wird.
Wenn ich also ehrlich sein soll: Ich kann auf nicht vorzeichenbehaftete Datentypen komplett verzichten. Soweit mir bekannt sind solche Typen ohnehin nur Relikte aus Zeiten, in denen es auf jedes einzelne Byte Speicherplatz ankam.
Wenn du 8 + 8 oder -8 + 8 rechnest, ändert sich das Bitmuster der hinteren 4 Bit des Ergebnisses nicht, also ich sehe keinen Vorteil in unsigned.
Wenn es auf Platz/Speicher ankommt, dann long[] und >>> oder << usw. verwenden (BitSet, ByteArrayOutputStream, …). Grüße
Edit: Wahrscheinlich werden’s die Entwickler sagen, was sie mit mutable Wrapper “erweiterter” Primitiver meinen.
Warum die Entwickler? Mutable Wrapper war meine ureigenste Wortschöpfung. Ich meine damit, dass ein Number-Objekt (also ein Wrapper) viel besser wär, wenn es davon Klassen mit veränderlichen Values gäbe, dann müsste man z.B. bei Wortzählern nicht immer selber was erfinden (Map<String, Integer> gegen Map<String, Counter>). Wobei so ein Counter auch wahnsinnig gut für übergroße Schleifenzähler verwendet werden kann, da dessen Bitbreite ja beliebig per Implementation festlegen kann. Sowas hatte ich mal implementiert, aber nie gebraucht. Eine For-Schleife sah dann ungefähr so aus:
private final long[] values;
Counter(long... values) {
this.values = values.clone();
}
boolean decrement() {
boolean isZero = true;
// ...bekomm ich auf die schnelle nicht mehr zusammen
return isZero;
}
public static void main(String[] args) {
for(Counter c = new Counter(1, 0); c.decrement();) {
// ...
}
}
}```
Naja, die oberen 4 Bit sind aber doch unterschiedlich. Ob’s nun einen Unterschied macht, und einem unsigneds einen Vorteil bringen, hängt halt vom Anwendungsbereich ab. Wenn man Zahlen nur für Arithmetik nutzt mag’s einem freilich egal sein.
Worüber ich mich z. B. jedesmal ärgere ist, das ein Inputstream - wenn man ihn en bloc einliest - Bytes von -128 bis +127 liefert anstatt von 0 bis 255. Diese Werte kann man so weder als Schleifengrenzen verwenden, noch als Arrayindizes, noch an sonstigen Stellen an denen Werte von 0-255 vorgesehen sind (wildes Beispiel: im Constructor der Klasse Color). Eigentlich kann man sie nur zum Rechnen gebrauchen, und das auch nur dann, falls dieser Wertebereich entsprechend vorgesehen ist. Ein Wertebereich von 0-255 ist aber durchaus gebräuchlich. Ich selber würde es daher sehr begrüßen, wenn es diesen auch in Java endlich gäbe. Dann müsste ich die Daten eines Inputstream nicht jedesmal explizit in nutzbare ints unwandeln…
[QUOTE=Dow_Jones;102921]Worüber ich mich z. B. jedesmal ärgere ist, das ein Inputstream - wenn man ihn en bloc einliest - Bytes von -128 bis +127 liefert anstatt von 0 bis 255.[/QUOTE]Mit en bloc, denk ich mal, meinst du per ByteArray. Nun ja, wenn man da einzelne Bytes als Zähler oder Indices braucht, kann man das ganz simpel per UND-Verknüpfung und einem int bewerkstelligen (siehe read()-Methode). Worüber ich mich seit der Einführung von “java.nio” argere, ist der Umstand, dass man in Streams immernoch keine ByteBuffer verwenden kann (ok, bei einigen, wenigen geht das afaik sogar). ByteBuffer würden nämlich so vieles einfacher machen, insbesondere, was die ByteOrder in manchen Dateitypen angeht. Die Tücke mit mit Bytewerten zwischen -128 und 127 wäre damit allemal gut gelöst.