Wie verwende ich die vorzeichenlose Ganzzahl in Java 8 und Java 9?

81

In der Oracle „Primitive Datentypen“ Seite , erwähnt sie , dass Java 8 Unterstützung für unsigned ints und sehnt sich fügt hinzu:

int: Standardmäßig ist der intDatentyp eine 32-Bit-Zweierkomplement-Ganzzahl mit Vorzeichen, die einen Minimalwert von –2 31 und einen Maximalwert von 2 31 –1 hat. In Java SE 8 und höher können Sie den intDatentyp verwenden, um eine vorzeichenlose 32-Bit-Ganzzahl darzustellen, die einen Minimalwert von 0 und einen Maximalwert von 2 32 −1 hat. Verwenden Sie die IntegerKlasse, um den intDatentyp als Ganzzahl ohne Vorzeichen zu verwenden. Weitere Informationen finden Sie im Abschnitt Die Zahlenklassen. Statische Methoden wie compareUnsigned, divideUnsignedetc wurden die hinzugefügt IntegerKlasse , um die arithmetischen Operationen für ganze Zahlen ohne Vorzeichen zu unterstützen.

long: Der longDatentyp ist eine 64-Bit-Zweierkomplement-Ganzzahl. Das Vorzeichen longhat einen Minimalwert von −2 63 und einen Maximalwert von 2 63 −1. In Java SE 8 und höher können Sie den longDatentyp verwenden, um ein vorzeichenloses 64-Bit darzustellen long, das einen Mindestwert von 0 und einen Höchstwert von 2 64 −1 hat. Verwenden Sie diesen Datentyp, wenn Sie einen Wertebereich benötigen, der breiter ist als der von int bereitgestellte. Die LongKlasse enthält auch Methoden wie compareUnsigned, divideUnsignedetc arithmetische Operationen für unsigned zu unterstützen long.

Ich finde jedoch keine Möglichkeit, ein vorzeichenloses Long oder eine Ganzzahl zu deklarieren. Der folgende Code gibt beispielsweise eine Compiler-Fehlermeldung aus: "Das Literal liegt außerhalb des Bereichs" (ich verwende natürlich Java 8), wenn es im Bereich liegen sollte (der zugewiesene Wert ist genau 2 64 −1). ::

public class Foo {
    static long values = 18446744073709551615L;
    
    public static void main(String[] args){
        System.out.println(values);
    }  
}

Gibt es also eine Möglichkeit, ein Int oder Long ohne Vorzeichen zu deklarieren?

Pabce
quelle
2
Was wird in Ihrer Long.MAX_VALUE-Konstante in Java 8 zurückgegeben?
Bruno Franco
21
Es gibt keine vorzeichenlose Ganzzahl oder vorzeichenlosen langen Typen. Wenn Sie eine der neuen Methoden verwenden, behandelt diese Methode eine 32-Bit- oder 64-Bit-Ganzzahl so, als wäre sie ohne Vorzeichen. Aber das ist alles. Der Variablentyp wird weiterhin signiert, und Sie müssen sich daran erinnern, dass Sie ihn als vorzeichenlose Nummer verwenden. Sie haben keine vorzeichenlosen Literale hinzugefügt, aber vielleicht fügen sie sie Java 9 hinzu, wenn genügend Leute sie nerven. :)
Ajb
5
Sie haben nichts wirklich geändert, außer die neuen Methoden hinzuzufügen.
Hot Licks
4
Soweit ich das beurteilen kann, haben sie lediglich Methoden hinzugefügt, die vorzeichenlose Werte zurückgeben können, aber nicht zulassen, dass Sie vorzeichenlose Werte deklarieren. Irgendwie albern, wenn du mich fragst, und ein echter Schmerz. Ich frage mich, ob eine Möglichkeit darin besteht, Integer.divideUnsigned zu verwenden, wobei ein Parameter 1 ist und der andere die Zahl, die Sie als vorzeichenlos behandeln möchten. Würde funktionieren, soweit ich das beurteilen kann, scheint aber eine wirklich dumme Art zu sein, Dinge zu tun.
Cluemein
@ajb Wie kann ich beim "Bugging" -Prozess behilflich sein, um endlich das richtige unsignierte in Java zu sehen? :)
Matthieu

Antworten:

51

Gemäß der von Ihnen veröffentlichten Dokumentation und diesem Blog-Beitrag gibt es keinen Unterschied, wenn Sie das Grundelement zwischen einem nicht signierten int / long und einem signierten deklarieren. Die "neue Unterstützung" ist das Hinzufügen der statischen Methoden in den Klassen Integer und Long, z . B. Integer.divideUnsigned . Wenn Sie diese Methoden nicht verwenden, ist Ihr "vorzeichenloses" Long über 2 ^ 63-1 nur ein einfaches altes Long mit einem negativen Wert.

Nach einem kurzen Blick sieht es nicht so aus, als gäbe es eine Möglichkeit, ganzzahlige Konstanten im Bereich außerhalb von +/- 2 ^ 31-1 oder +/- 2 ^ 63-1 für Longs zu deklarieren. Sie müssten den negativen Wert, der Ihrem positiven Wert außerhalb des Bereichs entspricht, manuell berechnen.

Sbodd
quelle
85

Nun, selbst in Java 8 longund intimmer noch signiert, behandeln sie nur einige Methoden so , als wären sie nicht signiert . Wenn Sie so ein vorzeichenloses longLiteral schreiben möchten , können Sie dies tun

static long values = Long.parseUnsignedLong("18446744073709551615");

public static void main(String[] args) {
    System.out.println(values); // -1
    System.out.println(Long.toUnsignedString(values)); // 18446744073709551615
}
kajacx
quelle
5
Eine Beobachtung, die ich dabei sehe, ist, dass die Bestellung verfälscht ist. Wenn ich von einem System ein Long ohne Vorzeichen erhalten würde (Twitter liefert übrigens solche IDs) und sie sortieren wollte, vielleicht weil ich wusste, dass sie chronologisch sind, wird alles, was über Long.MAX_VALUE hinausgeht, tatsächlich vor 0 als negativ angezeigt mit Javas Implementierung :-(. Stattdessen scheint es, dass man es auch so nach unten verschieben muss, dass vorzeichenlose 0 auf signierte Long.MIN_VALUE abgebildet werden.
David Smiley
10
@ DavidSmiley Guter Punkt. Um nicht signierte Longs zu sortieren, verwenden Sie Long.compareUnsigned oder übergeben Sie diese Methode als Komparator, um Funktionen zu sortieren.
kajacx
26
    // Java 8
    int vInt = Integer.parseUnsignedInt("4294967295");
    System.out.println(vInt); // -1
    String sInt = Integer.toUnsignedString(vInt);
    System.out.println(sInt); // 4294967295

    long vLong = Long.parseUnsignedLong("18446744073709551615");
    System.out.println(vLong); // -1
    String sLong = Long.toUnsignedString(vLong);
    System.out.println(sLong); // 18446744073709551615

    // Guava 18.0
    int vIntGu = UnsignedInts.parseUnsignedInt(UnsignedInteger.MAX_VALUE.toString());
    System.out.println(vIntGu); // -1
    String sIntGu = UnsignedInts.toString(vIntGu);
    System.out.println(sIntGu); // 4294967295

    long vLongGu = UnsignedLongs.parseUnsignedLong("18446744073709551615");
    System.out.println(vLongGu); // -1
    String sLongGu = UnsignedLongs.toString(vLongGu);
    System.out.println(sLongGu); // 18446744073709551615

    /**
     Integer - Max range
     Signed: From −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 – 1
     Unsigned: From 0 to 4,294,967,295 which equals 2^32 − 1

     Long - Max range
     Signed: From −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, from −(2^63) to 2^63 − 1
     Unsigned: From 0 to 18,446,744,073,709,551,615 which equals 2^64 – 1
     */
blueberry0xff
quelle
9
Sollte eine Erklärung hinzufügen, nicht nur Code da draußen werfen.
Cluemein
20

Es gibt keine Möglichkeit , ein Long oder Int ohne Vorzeichen in Java 8 oder Java 9 zu deklarieren. Einige Methoden behandeln sie jedoch so, als wären sie ohne Vorzeichen, zum Beispiel:

static long values = Long.parseUnsignedLong("123456789012345678");

Dies ist jedoch keine Deklaration der Variablen.

1ac0
quelle
3
Ich wundere mich, warum nicht. Sie hätten leicht Uint- und Ulong-Typen hinzufügen können
EKanadily
@docesam in diesem und diesem Dokument ist eine ausführliche Erklärung. Kurz gesagt, es wurde nur eine Methode zur vorzeichenlosen Manipulation der Integer-Klasse hinzugefügt. und wenn sie leicht hätten hinzufügen können , weiß ich nicht, warum sie es nicht tun werden
;-)
@ Ladislav DANKO gibt es umsichtige Leute, und da sind die anderen Jungs. Ich bin mir nicht sicher, ob es in diesem Fall umsichtig war oder nicht, aber ich habe den Eindruck, dass Orakel nicht so umsichtig ist.
EKanadily
1
@docesam Nein, sie konnten nicht "einfach uint und ulong Typen hinzufügen". Das würde eine Überarbeitung von JLS, JVM-Spezifikation, JNI, vielen Bibliotheken (wie java.util.Arrays), Reflektion und vielem mehr erfordern.
Nayuki
1
@ Michaelangel007 Hey, ich denke, wir nähern uns diesem Thema mit unterschiedlichen Hintergrundannahmen. Möchtest du mir eine E-Mail schreiben und wir werden über die Details sprechen?
Nayuki
4

Wenn die Verwendung einer Bibliothek eines Drittanbieters eine Option ist, gibt es jOOU (eine Spin-off-Bibliothek von jOOQ ), die Wrapper-Typen für vorzeichenlose Ganzzahlen in Java bietet. Das ist nicht genau das Gleiche wie die Unterstützung von primitiven Typen (und damit Bytecode) für vorzeichenlose Typen, aber vielleicht ist es immer noch gut genug für Ihren Anwendungsfall.

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

Alle diese Typen erstrecken sich java.lang.Numberund können in primitive Typen höherer Ordnung und konvertiert werden BigInteger.

(Haftungsausschluss: Ich arbeite für die Firma hinter diesen Bibliotheken)

Lukas Eder
quelle