在 Java 中声明一个 unsigned int
Posted
技术标签:
【中文标题】在 Java 中声明一个 unsigned int【英文标题】:Declaring an unsigned int in Java 【发布时间】:2012-04-08 21:30:54 【问题描述】:有没有办法?
或者问题也可以这样表述: 无符号的 Java 等价物是什么?
只是为了告诉你我正在查看 Java 的 String.hashcode()
实现的上下文。如果整数是 32 unsigned int,我想测试碰撞的可能性。
【问题讨论】:
Java 中没有无符号类型。 这篇文章可能对你有所帮助***.com/a/4449161/778687 似乎不是 AFAICT 的一种方式。相关:***.com/questions/430346/… 这取决于您要达到的目的。在大多数情况下,Java 中的所有整数都是有符号的。但是,您可以在一种特定情况下将有符号整数处理为无符号:您可以使用>>>
运算符而不是>>
来右移而不进行符号扩展。
另见How to use the unsigned Integer in Java 8 and Java 9?
【参考方案1】:
Java 没有 unsigned integers 的数据类型。
如果您需要存储较大的值,您可以定义 long
而不是 int
。
您也可以像使用无符号整数一样使用有符号整数。 two's complement representation 的好处是大多数操作(例如加法、减法、乘法和左移)在二进制级别上对于有符号和无符号整数都是相同的。然而,一些操作(除法、右移、比较和强制转换)是不同的。从 Java SE 8 开始,Integer
类中的新方法允许您充分使用 int
数据类型 to perform unsigned arithmetic:
在 Java SE 8 及更高版本中,您可以使用 int 数据类型来表示一个无符号的 32 位整数,其最小值为 0,最大值为 2^32-1。使用 Integer 类将 int 数据类型用作无符号整数。已将
compareUnsigned
、divideUnsigned
等静态方法添加到 Integer 类中,以支持无符号整数的算术运算。
请注意,int
变量在声明时仍然是有符号的,但现在可以通过在 Integer
类中使用这些方法来进行无符号运算。
【讨论】:
公平地说,对于许多项目来说,技术要求并没有那么严格,你确实可以承受这样“浪费”内存的代价。 我知道,我也明白Java的初衷。但例如智能手机不配置额外的内存。据我所知,他们通常使用 Java。不过好吧,我不想在 Java 程序员和其他人之间挑起战争。 对我来说,这不仅仅是浪费钱。当您在位级别上工作时,无符号更容易使用 从 Java 8 开始,这不再是真的。在 Java SE 8 及更高版本中,您可以使用int
数据类型来表示一个无符号的 32 位整数,其最小值为 0
,最大值为 2^32-1
。 - 见docs.oracle.com/javase/tutorial/java/nutsandbolts/…和docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
@7SpecialGems:我已经更新了答案以包含该信息。话虽如此,不可能声明无符号整数或排除负值,只能使用int
,就好像它通过各种方法无符号一样。【参考方案2】:
int 中的值是有符号还是无符号取决于位的解释方式 - Java 将位解释为有符号值(它没有无符号原语)。
如果您想要将一个 int 解释为无符号值(例如,您从 DataInputStream
读取一个您知道应该解释为无符号值的 int),那么您可以执行以下技巧。
int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffL;
请注意,十六进制文字是长文字而不是 int 文字很重要 - 因此末尾有“L”。
【讨论】:
对我来说这是最好的答案...我的数据来自 NFC 卡 UID,它可以有 4 或 8 个字节...如果是 4 个字节,我需要将其转换为unsigned int,我不能使用 ByteBuffer.getLong 因为它不是 64 位数据。谢谢。 为什么需要很长。你不能只做0xFFFFFF
并保留int 吗?【参考方案3】:
我们需要无符号数来模拟 mysql 的无符号 TINYINT
、SMALLINT
、INT
、BIGINT
在 jOOQ 中,这就是我们创建 jOOU 的原因,这是一个提供无符号整数包装类型的简约库Java中的数字。示例:
import static org.joou.Unsigned.*;
// and then...
UByte b = ubyte(1);
UShort s = ushort(1);
UInteger i = uint(1);
ULong l = ulong(1);
所有这些类型都扩展了java.lang.Number
,并且可以转换为高阶原始类型和BigInteger
。希望这会有所帮助。
(免责声明:我为这些库背后的公司工作)
【讨论】:
这听起来很方便!感谢提及。 :)【参考方案4】:对于无符号数,您可以使用来自 Guava library 的这些类:
UnsignedInteger UnsignedLong它们支持各种操作:
加 减号 次 模组 除以目前似乎缺少的是字节移位运算符。如果您需要这些,您可以使用 Java 中的 BigInteger。
【讨论】:
【参考方案5】:也许这就是你的意思?
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
【讨论】:
您正在为使用三元运算符而不是 if 语句的惰性输入而牺牲数万亿分之一秒的性能时间。不好。 (开玩笑) 你真的认为2 * (long) Integer.MAX_VALUE + 2
比0x1_0000_0000L
更容易理解吗?在这方面,为什么不简单地return signed & 0xFFFF_FFFFL;
?【参考方案6】:
对 16 位无符号整数使用 char
。
【讨论】:
Char 不是 32 位无符号整数,但 char 是内存增益的一个很好的答案。此链接:***.com/questions/1841461/unsigned-short-in-java(来自上面的 jqr)【参考方案7】:这里有很好的答案,但我没有看到任何按位运算的演示。就像 Visser(当前接受的答案)所说,Java 默认对整数进行签名(Java 8 有无符号整数,但我从未使用过它们)。事不宜迟,我们开始吧……
RFC 868 示例
如果你需要将一个无符号整数写入 IO 会发生什么?实际示例是当您想根据RFC 868 输出时间时。这需要一个 32 位、大端、无符号整数,用于编码自 12:00 A.M. 以来的秒数。 1900 年 1 月 1 日。您将如何编码?
像这样制作自己的无符号 32 位整数:
声明一个 4 字节(32 位)的字节数组
Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)
这会初始化数组,请参阅Are byte arrays initialised to zero in Java?。现在,您必须以大端顺序(如果您想破坏大端,则使用小端)来填充数组中的每个字节。假设您有一个 long 包含时间(长整数在 Java 中为 64 位长),称为 secondsSince1900
(仅使用前 32 位值,并且您已经处理了 Date 引用 1970 年 1 月 1 日上午 12:00 的事实),然后您可以使用逻辑 AND 从中提取位并将这些位移动到在强制转换为字节时不会被忽略的位置(数字),并以大端顺序排列。
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
我们的my32BitUnsignedInteger
现在等效于符合 RCF 868 标准的无符号 32 位大端整数。是的,长数据类型是有符号的,但我们忽略了这个事实,因为我们假设 secondsSince1900 只使用了低 32 位)。由于将 long 强制转换为一个字节,所有高于 2^7 的位(十六进制的前两位)都将被忽略。
参考来源:Java Network Programming,第 4 版。
【讨论】:
这是新数组的java实现吗?Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)
这对我来说只是一个小小的“嗯”。我记得你应该这样做Byte[] my32BitUnsignedInteger = new Byte[4]
如果我错了,请纠正我。
@Yolomep 是的,它是 Java 语法。将括号附加到类型或名称是可以的。
哇。我不知道。我认为这种数组声明只适用于 c++。
你的字节是装箱的类。你想使用byte[] array = new byte[4]
【参考方案8】:
您似乎可以通过在使用值之前对值执行“逻辑与”来处理签名问题:
示例(byte[]
header[0]
的值为 0x86
):
System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));
结果:
Integer -122 = 134
【讨论】:
【参考方案9】:刚刚制作了这段代码,它将“this.altura”从负数转换为正数。希望对有需要的人有所帮助
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);
【讨论】:
【参考方案10】:您可以使用 Math.abs(number) 函数。它返回一个正数。
【讨论】:
挑剔:如果你传入MIN_VALUE
则不会
@kyo722 我无法想象这会返回一个无符号原语范围内的正值。
挑剔#2:如果你传入0
,则不会以上是关于在 Java 中声明一个 unsigned int的主要内容,如果未能解决你的问题,请参考以下文章