【问题标题】:Declaring an unsigned int in Java在 Java 中声明一个 unsigned int
【发布时间】:2012-04-08 21:30:54
【问题描述】:

有没有办法在 Java 中声明一个 unsigned int?

或者问题也可以这样表述: 无符号的 Java 等价物是什么?

只是为了告诉你我正在查看 Java 的 String.hashcode() 实现的上下文。如果整数是 32 unsigned int,我想测试碰撞的可能性。

【问题讨论】:

标签: java integer unsigned


【解决方案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 数据类型用作无符号整数。已将 compareUnsigneddivideUnsigned 等静态方法添加到 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 的无符号 TINYINTSMALLINTINTBIGINTjOOQ 中,这就是我们创建 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 的这些类:

它们支持各种操作:

  • 减号
  • 模组
  • 除以

目前似乎缺少的是字节移位运算符。如果您需要这些,您可以使用 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 + 20x1_0000_0000L更容易理解吗?在这方面,为什么不简单地return signed & 0xFFFF_FFFFL;
    【解决方案6】:

    对 16 位无符号整数使用 char

    【讨论】:

    【解决方案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,则不会
        猜你喜欢
        • 1970-01-01
        • 2019-05-04
        • 2013-08-17
        • 2020-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多