Deklarieren eines vorzeichenlosen int in Java

316

Gibt es eine Möglichkeit, ein vorzeichenloses int in Java zu deklarieren?

Oder die Frage könnte auch so lauten: Was ist das Java-Äquivalent von unsigned?

Nur um Ihnen den Kontext zu erläutern, in dem ich mir die Implementierung von Java angesehen habe String.hashcode(). Ich wollte die Möglichkeit einer Kollision testen, wenn die Ganzzahl 32 unsigned int wäre.

Hartnäckig
quelle
7
In Java gibt es keine vorzeichenlosen Typen.
Andrew Logvinov
1
Dieser Beitrag könnte Ihnen helfen stackoverflow.com/a/4449161/778687
Tusar
2
Scheint kein AFAICT zu sein. Siehe auch
James Manning
11
Dies hängt von dem Zweck ab, den Sie erreichen möchten. In den meisten Fällen sind alle Ganzzahlen in Java signiert. Sie können eine vorzeichenbehaftete Ganzzahl jedoch in einem bestimmten Fall als vorzeichenlos behandeln : Sie können ohne Vorzeichenverlängerung nach rechts verschieben, indem Sie stattdessen den >>>Operator verwenden >>.
Dasblinkenlight

Antworten:

310

Java hat keinen Datentyp für vorzeichenlose Ganzzahlen .

Sie können ein longanstelle eines definieren, intwenn Sie große Werte speichern müssen.

Sie können eine vorzeichenbehaftete Ganzzahl auch so verwenden, als wäre sie nicht vorzeichenbehaftet. Der Vorteil der Zweierkomplementdarstellung besteht darin, dass die meisten Operationen (wie Addition, Subtraktion, Multiplikation und Linksverschiebung) auf Binärebene für vorzeichenbehaftete und vorzeichenlose Ganzzahlen identisch sind. Einige Operationen (Division, Rechtsverschiebung, Vergleich und Casting) sind jedoch unterschiedlich. Ab Java SE 8 können Sie mit neuen Methoden in der IntegerKlasse den intDatentyp vollständig verwenden , um vorzeichenlose Arithmetik auszuführen :

In Java SE 8 und höher können Sie den Datentyp int verwenden, um eine vorzeichenlose 32-Bit-Ganzzahl darzustellen, die einen Mindestwert von 0 und einen Höchstwert von 2 ^ 32-1 hat. Verwenden Sie die Integer-Klasse, um den Datentyp int als Ganzzahl ohne Vorzeichen zu verwenden. Statische Methoden wie compareUnsigned, divideUnsignedusw. wurden die Integer - Klasse hinzugefügt , um die arithmetischen Operationen für ganze Zahlen ohne Vorzeichen zu unterstützen.

Beachten Sie, dass intVariablen beim Deklarieren immer noch signiert sind, aber mit diesen Methoden in der IntegerKlasse jetzt eine Arithmetik ohne Vorzeichen möglich ist .

Simeon Visser
quelle
11
Um fair zu sein, für viele Projekte sind die technischen Anforderungen nicht so streng und Sie können es sich tatsächlich leisten, Speicher so zu "verschwenden".
Simeon Visser
6
Ich weiß, ich verstehe auch den ursprünglichen Zweck von Java. Zum Beispiel verfügen Smartphones nicht über zusätzlichen Speicher. Soweit ich weiß, verwenden sie normalerweise Java. Aber nun, ich möchte keinen Krieg zwischen Java-Programmierern und den anderen beginnen.
Tomáš Zato - Wiedereinsetzung Monica
122
Für mich geht es nicht nur darum, Geld zu verschwenden. Wenn Sie auf einer Bit-Ebene arbeiten, ist es einfach einfacher, mit unsigned zu arbeiten
Cruncher
24
Ab Java 8 ist dies nicht mehr der Fall . In Java SE 8 und höher können Sie den intDatentyp verwenden, um eine vorzeichenlose 32-Bit-Ganzzahl darzustellen, die einen Mindestwert von 0und einen Höchstwert von hat 2^32-1. - Siehe docs.oracle.com/javase/tutorial/java/nutsandbolts/… und docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie
2
@ 7SpecialGems: Ich habe die Antwort aktualisiert, um diese Informationen aufzunehmen. Abgesehen davon ist es nicht möglich, vorzeichenlose Ganzzahlen zu deklarieren oder negative Werte auszuschließen. Es ist nur möglich, eine intmit verschiedenen Methoden so zu verwenden, als ob sie vorzeichenlos wäre.
Simeon Visser
70

In Java 8 gibt es eine API für vorzeichenlose Ganzzahlen und Long!

Baraber
quelle
1
@stas Ich habe Schwierigkeiten, die Verwendung zu verstehen, und große Probleme damit, vorzeichenlose Datentypen verwenden zu können. Aus den verschiedenen Online-Quellen, aus denen ich lese, geht es anscheinend nur darum, den Maximalwert zu erweitern, und die implizite Natur garantiert, dass es sich um eine positive Zahl handelt. Ist mein Verständnis richtig oder gibt es andere wichtige Gründe? Jetzt, da die IntegerKlasse in Java 8 die Verwendung von int ohne Vorzeichen erlaubt, ist dies der Unterschied zwischen nur Platz und Geschwindigkeit (da sie in C / C ++ primitiv sind, während es in Java ein ganzer Objekt-Wrapper ist)
Abdul
2
@Abdul - Wenn Sie auf Bitebene arbeiten (normalerweise, weil Sie mit Hardware verbunden sind), müssen Sie Werte angeben, um sich auf eine bestimmte Weise zu verhalten. dh - Rollover nach 11111111 auf 00000000 usw. Die Verwendung von signierten anstelle von nicht signierten kann die CRC-Berechnungen beschädigen usw. Es ist kein Show-Stopper, sondern nur Zeitverschwendung.
Lorne K
3
@ Lorne K: In Java wird ein Rollover durchgeführt int, auch wenn diese signiert sind. Es ist C / C ++, bei dem nicht signiertes Rollover ausgeführt wird, signiertes jedoch beim Überlauf „Undefiniertes Verhalten“ verursacht. Wenn "Überrollen" Ihr einziges Anliegen ist, brauchen Sie kein unsigniertes. Ich denke, deshalb funktionieren CRC-Routinen usw. in Java ohne zusätzlichen Aufwand. Aus diesem Grund fügt die neue API nur Parsen, Formatieren, Vergleichen, Teilen und Rest hinzu. Alle anderen Operationen, nämlich alle Bitmanipulationen, aber auch Addition, Subtraktion, Multiplikation usw., machen sowieso das Richtige.
Holger
4
@Ciprian Tomoiaga: Beim Hinzufügen mit Rollover hängen die Bitmuster der Eingabe und des Ergebnisses nicht davon ab, ob Sie sie als vorzeichenbehaftete oder vorzeichenlose Nummer interpretieren. Wenn Sie Geduld haben, können Sie es mit allen 2⁶⁵ Kombinationen versuchen ...
Holger
3
@ Holger danke für die Erklärung! In der Tat stellt sich heraus, dass wir deshalb tatsächlich das 2er-Komplement verwenden. Ich habe es mit einigen 2 ^ 8 Kombinationen versucht ^^
Ciprian Tomoiagă
66

Ob ein Wert in einem int vorzeichenbehaftet oder vorzeichenlos ist, hängt davon ab, wie die Bits interpretiert werden. Java interpretiert Bits als vorzeichenbehafteten Wert (es gibt keine vorzeichenlosen Grundelemente).

Wenn Sie ein int haben, das Sie als vorzeichenlosen Wert interpretieren möchten (z. B. wenn Sie ein int aus einem DataInputStream lesen, von dem Sie wissen, dass es einen vorzeichenlosen Wert enthält), können Sie den folgenden Trick ausführen.

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

Beachten Sie, dass es wichtig ist, dass das Hex-Literal ein langes Literal ist, kein int-Literal - daher das 'l' am Ende.

Zsolt Safrany
quelle
3
Für mich ist dies die beste Antwort ... Meine Daten stammen von einer NFC-Karten-UID, die 4 oder 8 Bytes haben kann ... Bei 4 Bytes musste ich sie in ein vorzeichenloses int umwandeln, und ich konnte nicht Verwenden Sie ByteBuffer.getLong, da es sich nicht um 64-Bit-Daten handelt. Vielen Dank.
Loudenvier
Warum muss es lange dauern? Kannst du nicht einfach 0xFFFFFFdas int machen und behalten?
Displee
19

Wir benötigten Zahlen ohne Vorzeichen zu modellieren MySQL ohne Vorzeichen TINYINT, SMALLINT, INT, BIGINTin jOOQ , weshalb wir geschaffen haben jOOU , ein minimalistisches Bibliothek Angebot Wrapper - Typen für unsigned Integer - Zahlen in Java. Beispiel:

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. Hoffe das hilft.

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

Lukas Eder
quelle
Das klingt sehr praktisch! Vielen Dank für die Erwähnung. :)
Lucas Sousa
7

Für vorzeichenlose Nummern können Sie diese Klassen aus der Guava-Bibliothek verwenden :

Sie unterstützen verschiedene Operationen:

  • Plus
  • Minus
  • mal
  • mod
  • geteilt durch

Das, was im Moment zu fehlen scheint, sind Byte-Shift-Operatoren. Wenn Sie diese benötigen, können Sie BigInteger von Java aus verwenden.

Andrejs
quelle
4

Verwendung charfür 16-Bit-Ganzzahlen ohne Vorzeichen.

Steven Stewart-Gallus
quelle
Char sind keine 32-Bit-Ints ohne Vorzeichen, aber Char ist eine gute Antwort für den Speichergewinn. Dieser Link: stackoverflow.com/questions/1841461/unsigned-short-in-java (von jqr oben)
blobmaster
2

Vielleicht hast du das gemeint?

long getUnsigned(int signed) {
    return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
  • getUnsigned(0) → 0
  • getUnsigned(1) → 1
  • getUnsigned(Integer.MAX_VALUE) → 2147483647
  • getUnsigned(Integer.MIN_VALUE) → 2147483648
  • getUnsigned(Integer.MIN_VALUE + 1) → 2147483649
Matthias Ronge
quelle
Sie opfern eine Zillionstelsekunde Leistungszeit für das verzögerte Tippen mit ternären Operatoren anstelle von if-Anweisungen. Nicht gut. (Scherz)
Ytpillai
5
Denken Sie wirklich, 2 * (long) Integer.MAX_VALUE + 2ist leichter zu verstehen als 0x1_0000_0000L? Warum nicht einfach return signed & 0xFFFF_FFFFL;?
Holger
2

Es scheint, dass Sie das Signaturproblem lösen können, indem Sie ein "logisches UND" für die Werte ausführen, bevor Sie sie verwenden:

Beispiel (Wert von byte[] header[0]is 0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

Ergebnis:

Integer -122 = 134
Carsten Semark
quelle
2

Hier gibt es gute Antworten, aber ich sehe keine Demonstrationen von bitweisen Operationen. Wie Visser (die derzeit akzeptierte Antwort) sagt, signiert Java standardmäßig Ganzzahlen (Java 8 hat Ganzzahlen ohne Vorzeichen, aber ich habe sie nie verwendet). Lass es uns ohne weiteres tun ...

RFC 868 Beispiel

Was passiert, wenn Sie eine vorzeichenlose Ganzzahl in IO schreiben müssen? Ein praktisches Beispiel ist, wenn Sie die Zeit gemäß RFC 868 ausgeben möchten . Dies erfordert eine 32-Bit-Big-Endian-Ganzzahl ohne Vorzeichen, die die Anzahl der Sekunden seit dem 1. Januar 1900 um 00:00 Uhr codiert. Wie würden Sie dies codieren?

Erstellen Sie Ihre eigene vorzeichenlose 32-Bit-Ganzzahl wie folgt:

Deklarieren Sie ein Byte-Array mit 4 Bytes (32 Bit).

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

Dadurch wird das Array initialisiert, siehe Werden Byte-Arrays in Java auf Null initialisiert? . Jetzt müssen Sie jedes Byte im Array mit Informationen in der Big-Endian-Reihenfolge füllen (oder Little-Endian, wenn Sie Chaos anrichten möchten). Angenommen, Sie haben eine lange Zeit, die die Zeit enthält (lange Ganzzahlen sind in Java 64 Bit lang secondsSince1900) Sie können das logische UND verwenden, um Bits daraus zu extrahieren und diese Bits in Positionen (Ziffern) zu verschieben, die beim Zusammenführen in ein Byte und in Big-Endian-Reihenfolge nicht ignoriert werden.

my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed

Unsere my32BitUnsignedIntegerentspricht jetzt einer vorzeichenlosen 32-Bit-Big-Endian-Ganzzahl, die dem RCF 868-Standard entspricht. Ja, der lange Datentyp ist signiert, aber wir haben diese Tatsache ignoriert, da wir davon ausgegangen sind, dass der secondSince1900 nur die unteren 32 Bit verwendet hat. Da das Long in ein Byte umgewandelt wird, werden alle Bits, die höher als 2 ^ 7 sind (die ersten beiden Ziffern in Hex), ignoriert.

Quelle angegeben: Java Network Programming, 4. Ausgabe.

Jonathan Komar
quelle
1

Ich habe gerade diesen Code erstellt, der "this.altura" von einer negativen in eine positive Zahl umwandelt. Hoffe das hilft jemandem in Not

       if(this.altura < 0){    

                        String aux = Integer.toString(this.altura);
                        char aux2[] = aux.toCharArray();
                        aux = "";
                        for(int con = 1; con < aux2.length; con++){
                            aux += aux2[con];
                        }
                        this.altura = Integer.parseInt(aux);
                        System.out.println("New Value: " + this.altura);
                    }
Romulo
quelle
-19

Sie können die Funktion Math.abs (Nummer) verwenden. Es wird eine positive Zahl zurückgegeben.

kyo722
quelle
12
Nitpick: nicht, wenn Sie vorbeikommenMIN_VALUE
Dennis Meng
2
@ kyo722 Ich kann mir nicht vorstellen, dass dies einen positiven Wert im Bereich der vorzeichenlosen Grundelemente zurückgibt.
Florian R. Klein
1
Nitpick # 2: nicht, wenn Sie in0
Genisage