2011-02-02 3 views
26

Exemple code:La façon la plus élégante pour convertir un octet à un int en Java

int a = 255; 
byte b = (byte) a; 
int c = b & 0xff; // Here be dragons 
System.out.println(a); 
System.out.println(b); 
System.out.println(c); 

Nous commençons par une valeur entière de 255, le convertir en un octet (devenant -1), puis reconvertir à un int en utilisant une formule magique. Le résultat attendu est:

255 
-1 
255 

Je me demande si ce a & 0xff est la façon la plus élégante de cette conversion. checkstyle par exemple se plaint de l'utilisation d'un nombre magique à cet endroit et ce n'est pas une bonne idée d'ignorer cette valeur pour cette vérification parce que dans d'autres endroits 255 peut vraiment être un nombre magique qui devrait être évité. Et c'est assez ennuyeux de définir une constante pour ce genre de choses par moi-même. Donc, je me demande s'il existe une méthode standard dans JRE qui fait cette conversion à la place? Ou peut-être une constante déjà définie avec la plus haute valeur d'octet non signé (similaire à Byte.MAX_VALUE qui est la plus haute valeur signée)

Donc pour garder la question courte: Comment puis-je convertir un octet en un int sans utiliser un nombre magique ?

Ok, jusqu'à présent, les possibilités suivantes ont été mentionnées:

  • et continuer à utiliser & 0xff ignorer le nombre magique 255 checkstyle. Inconvénient: Les autres endroits qui peuvent utiliser ce numéro dans un autre domaine (pas les opérations sur les bits) ne sont pas vérifiés dans ce cas également. Avantage: Court et facile à lire.
  • Définissez ma propre constante et utilisez le code & SomeConsts.MAX_UNSIGNED_BYTE_VALUE. Inconvénient: Si j'en ai besoin dans différentes classes, je dois définir ma propre classe constante juste pour cette constante constante. Avantage: Pas de nombres magiques ici. Faites des calculs intelligents comme b & ((1 << Byte.SIZE) - 1). La sortie du compilateur est probablement la même car elle est optimisée à une valeur constante. Inconvénient: Assez de code, difficile à lire. Avantage: Tant que 1 n'est pas défini comme nombre magique (checkstyle l'ignore par défaut), nous n'avons aucun nombre magique ici et nous n'avons pas besoin de définir des constantes personnalisées. Et quand les octets sont redéfinis pour être 16 bits un jour (juste plaisantant) alors cela fonctionne toujours parce que alors Byte.SIZE aura 16 et non 8.

Y a-t-il plus d'idées? Peut-être une autre opération astucieuse qui est plus courte que celle ci-dessus et n'utilise que des nombres comme 0 et 1?

+0

Je ne suis pas tout à fait certain de ce que vous êtes vraiment essayer de faire ici, ou plutôt, pourquoi . ** ATTENTION: Ne mélangez pas les octets et les caractères! ** Un octet ne peut contenir que des caractères ASCII 7 bits * pas des caractères Java! * Les caractères Unicode ont une largeur de 21 bits, pas seulement 7 bits ** ni même 15/16 bits, * * non plus. Java représente en interne les caractères en unités de code UTF-16 de largeur variable (c'est-à-dire 1 ou 2) dans la plupart des situations (* exception: * java.unit.regex utilise nécessairement UTF-32 pour ses motifs). Vous ne pouvez pas raisonnablement masquer/sauvegarder seulement les 7 bits de poids faible d'une quantité de 21 bits et être laissé avec quelque chose de sensé et significatif. – tchrist

+0

@tchrist: Je n'ai jamais mentionné de personnages ici. C'est juste des octets. Octets de 8 bits. Ni plus ni moins. – kayahr

+0

Yah, d'accord. Mais * signé * quantités de 8 bits. – tchrist

Répondre

17

Cette est la manière standard de faire cette transformation. Si vous voulez vous débarrasser des plaintes checkstyle, essayez de définir une constante, il pourrait aider:

public final static int MASK = 0xff; 

BTW - garder à l'esprit, qu'il est encore une conversion personnalisée. byte est un type de données signé. Par conséquent, un byte ne peut jamais contenir la valeur 255. Un octet peut stocker le motif de bits 1111 1111 mais cela représente la valeur entière -1. Donc, en fait, vous faites des opérations sur les bits - et les opérations sur les bits toujours nécessitent des nombres magiques.


BTW-2: Oui, il existe une constante Byte.MAX_VALUE mais cela est - parce que byte est signé - défini comme 2 -1 (= 127). Donc cela ne va pas aider dans votre cas. Vous avez besoin d'une constante d'octet pour -1.

+0

On dirait qu'il n'y a plus d'idées qui arrivent. J'accepte donc celui qui a le plus de votes. Merci pour vos opinions. – kayahr

10

Ignore checkstyle. 0xFF est pas un nombre magique. Si vous définissez une constante pour cela, la constante est une constante magique, ce qui est beaucoup moins compréhensible que 0xFF lui-même. Chaque programmeur éduqué dans les derniers siècles devrait être plus familier avec 0xFF qu'avec sa petite amie, le cas échéant.

Devrions-nous écrire du code comme celui-ci?

for(int i = Math.ZERO; ...) 
2

j'ai écrit une méthode pour cela comme

public static int unsigned(byte x) { 
    return int (x & 0xFF); 
} 

qui est surchargé pour les paramètres court et int, trop (où int est étendu à long).

Au lieu de 0xFF, vous pouvez utiliser Byte.MAX_VALUE + Byte.MAX_VALUE + 1 pour garder FindBug fermé, mais je considérerais qu'il s'agit d'une obfuscation. Et c'est trop facile de se tromper (les versions précédentes).

+1

Byte.MAX_VALUE + Byte.MAX_VALUE est 254 et non 255. Je pourrais utiliser (Byte.MAX_VALUE << 1) + 1 à la place (1 est déjà défini comme NON magique par checkstyle) mais ... eh bien ... Non: -) – kayahr

+0

Thx pour la correction, en fait, une constante comme Byte.ALL_ONES serait bien. – maaartinus

+0

Qu'en est-il de '(octet) (- 1)'? –

1

Java 8 fournit Byte.toUnsignedInt et Byte.toUnsignedLong (probablement pour très gros octets) Méthodes:

byte b = (byte)255; 
int c = Byte.toUnsignedInt(b); // 255 
long asLong = Byte.toUnsignedLong(b); // 255 
Questions connexes