Déclaration d'un int non signé en Java


317

Existe-t-il un moyen de déclarer un int non signé en Java?

Ou la question peut être formulée ainsi: quel est l'équivalent Java de unsigned?

Juste pour vous dire le contexte dans lequel je regardais l'implémentation de Java String.hashcode(). Je voulais tester la possibilité de collision si l'entier était 32 entier non signé.


7
Il n'y a pas de types non signés en Java.
Andrew Logvinov

1
Ce message pourrait vous aider stackoverflow.com/a/4449161/778687
tusar

2
Ne semble pas être un moyen AFAICT. Connexe: stackoverflow.com/questions/430346/…
James Manning

11
Cela dépend du but que vous essayez d'atteindre. Dans la plupart des cas, tous les entiers en Java sont signés. Cependant, vous pouvez traiter un entier signé comme non signé dans un cas spécifique: vous pouvez déplacer vers la droite sans extension de signe en utilisant l' >>>opérateur au lieu de >>.
dasblinkenlight

Réponses:


311

Java n'a pas de type de données pour les entiers non signés .

Vous pouvez définir un longau lieu d'un intsi vous avez besoin de stocker de grandes valeurs.

Vous pouvez également utiliser un entier signé comme s'il n'était pas signé. L'avantage de la représentation du complément à deux est que la plupart des opérations (telles que l'addition, la soustraction, la multiplication et le décalage vers la gauche) sont identiques au niveau binaire pour les entiers signés et non signés. Cependant, quelques opérations (division, décalage à droite, comparaison et coulée) sont différentes. Depuis Java SE 8, les nouvelles méthodes de la Integerclasse vous permettent d'utiliser pleinement le inttype de données pour effectuer une arithmétique non signée :

Dans Java SE 8 et versions ultérieures, vous pouvez utiliser le type de données int pour représenter un entier 32 bits non signé, qui a une valeur minimale de 0 et une valeur maximale de 2 ^ 32-1. Utilisez la classe Integer pour utiliser le type de données int comme un entier non signé. Des méthodes statiques comme compareUnsigned, divideUnsignedetc. ont été ajoutées à la classe Integer pour prendre en charge les opérations arithmétiques pour les entiers non signés.

Notez que les intvariables sont toujours signées lorsqu'elles sont déclarées mais l'arithmétique non signée est désormais possible en utilisant ces méthodes dans la Integerclasse.


11
Pour être juste, pour de nombreux projets, les exigences techniques ne sont pas si strictes et vous pouvez en effet vous permettre de "gaspiller" de la mémoire comme ça.
Simeon Visser

6
Je sais, je comprends aussi le but originel de Java. Mais par exemple, les smartphones ne disposent pas de mémoire supplémentaire. Et ils utilisent généralement Java, pour autant que je sache. Mais bon, je ne veux pas déclencher une guerre entre les programmeurs Java et les autres.
Tomáš Zato - Rétablir Monica

122
Pour moi, ce n'est pas seulement un cas de gaspillage d'argent. Lorsque vous travaillez à un niveau peu élevé, le non signé est tout simplement plus facile à
utiliser

24
Depuis Java 8, ce n'est plus le cas . Dans Java SE 8 et versions ultérieures, vous pouvez utiliser le inttype de données pour représenter un entier 32 bits non signé, qui a une valeur minimale de 0et une valeur maximale de 2^32-1. - voir docs.oracle.com/javase/tutorial/java/nutsandbolts/… et docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7SpecialGems: j'ai mis à jour la réponse pour inclure ces informations. Cela étant dit, il n'est pas possible de déclarer des entiers non signés ou d'exclure des valeurs négatives, il est uniquement possible d'utiliser un intcomme s'il n'était pas signé en utilisant diverses méthodes.
Simeon Visser du

70

1
@stas J'ai de la difficulté à comprendre l'utilisation et beaucoup à avoir la possibilité d'utiliser des types de données non signés. D'après les différentes sources en ligne que j'ai lues, il semble que cela tourne autour de l'élargissement de la valeur maximale, et la garantie implicite par nature qu'il s'agit d'un nombre positif. Ma compréhension est-elle correcte ou existe-t-il d'autres raisons majeures? De plus, maintenant que la Integerclasse de Java 8 permet d'utiliser un entier non signé, il y a la différence entre l'espace et la vitesse (car en C / C ++, ils sont primitifs, tandis qu'en Java, c'est un wrapper d'objet entier)
Abdul

2
@Abdul - lorsque vous travaillez au niveau du bit (généralement parce que vous vous connectez avec du matériel), vous devez définir des valeurs pour vous comporter d'une certaine manière. c'est-à-dire - survoler après 11111111 à 00000000, etc. Utiliser signé au lieu de non signé peut casser les calculs CRC, etc. Ce n'est pas un arrêt de spectacle, juste du temps perdu.
Lorne K

3
@Lorne K: en Java, intles roll-over, même s'ils sont signés. C'est C / C ++ où le non signé est retourné, mais le signé provoque un «comportement indéfini» en cas de débordement. Si le «roulement» est votre seule préoccupation, vous n'avez pas besoin de non signé. Je suppose que c'est pourquoi les routines CRC, etc. fonctionnent en Java sans efforts supplémentaires. Et c'est pourquoi la nouvelle API ajoute uniquement l'analyse, le formatage, les comparaisons, la division et le reste. Toutes les autres opérations, à savoir toutes les manipulations de bits, mais aussi l'addition, la soustraction, la multiplication, etc. font de toute façon la bonne chose.
Holger

4
@Ciprian Tomoiaga: pour l'ajout avec survol, les modèles de bits de l'entrée et le résultat ne dépendent pas de savoir si vous l'interprétez comme un numéro signé ou non signé. Si vous avez de la patience, vous pouvez l'essayer avec toutes les combinaisons 2⁶⁵…
Holger

3
@ Holger merci pour l'explication! En effet, il s'avère que c'est pourquoi nous utilisons en fait le complément à 2. J'ai essayé avec quelques 2 ^ 8 combinaisons ^^
Ciprian Tomoiagă

66

Le fait qu'une valeur dans un entier soit signée ou non dépend de la façon dont les bits sont interprétés - Java interprète les bits comme une valeur signée (il n'a pas de primitives non signées).

Si vous avez un int que vous souhaitez interpréter comme une valeur non signée (par exemple, vous lisez un int à partir d'un DataInputStream dont vous savez qu'il contient une valeur non signée), vous pouvez effectuer l'astuce suivante.

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

Notez qu'il est important que le littéral hexadécimal soit un long littéral, pas un littéral int - d'où le «l» à la fin.


3
Pour moi, c'est la meilleure réponse ... Mes données proviennent d'un UID de carte NFC, qui peut avoir 4 ou 8 octets ... Dans le cas de 4 octets, je devais le convertir en un entier non signé, et je ne pouvais pas utilisez ByteBuffer.getLong car il ne s'agissait pas de données 64 bits. Merci.
Loudenvier

Pourquoi faut-il que ce soit long. Tu ne peux pas juste faire 0xFFFFFFet garder l'int?
Displee

19

Nous avions besoin d'un nombre non signés modèle non signé de MySQL TINYINT, SMALLINT, INT, BIGINTdans jOOQ , ce qui est la raison pour laquelle nous avons créé jOOU , une offre bibliothèque wrapper types pour minimalistic nombres entiers non signés en Java. Exemple:

import static org.joou.Unsigned.*;

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

Tous ces types s'étendent java.lang.Numberet peuvent être convertis en types primitifs d'ordre supérieur et BigInteger. J'espère que cela t'aides.

(Avertissement: je travaille pour l'entreprise derrière ces bibliothèques)


Cela semble très pratique! Merci d'avoir mentionné. :)
Lucas Sousa

7

Pour les numéros non signés, vous pouvez utiliser ces classes de la bibliothèque Guava :

Ils prennent en charge diverses opérations:

  • plus
  • moins
  • fois
  • mod
  • divisé par

Ce qui semble manquer pour le moment, ce sont les opérateurs de décalage d'octet. Si vous en avez besoin, vous pouvez utiliser BigInteger de Java.



2

C'est peut-être ce que vous vouliez dire?

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

Vous sacrifiez un milliardième de seconde de temps de performance pour une saisie paresseuse avec des opérateurs ternaires au lieu d'instructions if. Pas bon. (blague)
ytpillai

5
Pensez-vous vraiment que 2 * (long) Integer.MAX_VALUE + 2c'est plus facile à comprendre que 0x1_0000_0000L? À cet égard, pourquoi pas simplement return signed & 0xFFFF_FFFFL;?
Holger

2

Il semble que vous pouvez gérer le problème de signature en effectuant un "ET logique" sur les valeurs avant de les utiliser:

Exemple (la valeur de byte[] header[0]est 0x86):

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

Résultat:

Integer -122 = 134

2

Il y a de bonnes réponses ici, mais je ne vois aucune démonstration d'opérations au niveau du bit. Comme Visser (la réponse actuellement acceptée) le dit, Java signe des entiers par défaut (Java 8 a des entiers non signés, mais je ne les ai jamais utilisés). Sans plus tarder, faisons-le ...

Exemple RFC 868

Que se passe-t-il si vous devez écrire un entier non signé dans IO? Un exemple pratique est lorsque vous souhaitez sortir l'heure conformément à la RFC 868 . Cela nécessite un entier non signé 32 bits, big-endian, qui code le nombre de secondes depuis le 1er janvier 1900 à 00h00. Comment encoderiez-vous cela?

Créez votre propre entier 32 bits non signé comme ceci:

Déclarez un tableau d'octets de 4 octets (32 bits)

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

Cela initialise le tableau, voir Les tableaux d'octets sont - ils initialisés à zéro en Java? . Vous devez maintenant remplir chaque octet du tableau avec des informations dans l'ordre big-endian (ou little-endian si vous voulez faire des ravages). En supposant que vous ayez un long contenant l'heure (les entiers longs ont 64 bits de long en Java) appelé secondsSince1900(qui n'utilise que les 32 premiers bits, et que vous avez géré le fait que la date fait référence à 00h00 le 1er janvier 1970), alors vous pouvez utiliser le ET logique pour en extraire des bits et les déplacer dans des positions (chiffres) qui ne seront pas ignorées lors de la compression dans un octet, et dans l'ordre big-endian.

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

Notre my32BitUnsignedIntegerest maintenant équivalent à un entier non signé de 32 bits, big-endian, conforme à la norme RCF 868. Oui, le type de données long est signé, mais nous avons ignoré ce fait, car nous avons supposé que le secondsSince1900 n'utilisait que les 32 bits inférieurs). En raison de la conversion du long en octet, tous les bits supérieurs à 2 ^ 7 (les deux premiers chiffres en hexadécimal) seront ignorés.

Source référencée: Java Network Programming, 4th Edition.


1

Je viens de faire ce morceau de code, qui convertit "this.altura" du nombre négatif en nombre positif. J'espère que cela aide quelqu'un dans le besoin

       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);
                    }

-19

Vous pouvez utiliser la fonction Math.abs (nombre). Il renvoie un nombre positif.


12
nitpick: pas si vous passezMIN_VALUE
Dennis Meng

2
@ kyo722 Je ne peux pas imaginer que cela retournera une valeur positive dans la gamme des primitives non signées.
Florian R. Klein

1
nitpick # 2: pas si vous passez0
genisage
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.