【问题标题】:How to use the unsigned Integer in Java 8 and Java 9?如何在 Java 8 和 Java 9 中使用无符号整数?
【发布时间】:2014-10-22 17:48:15
【问题描述】:

在 Oracle “原始数据类型”page 中,它提到 Java 8 增加了对无符号整数和长整数的支持:

int:默认情况下,int 数据类型为 32 位有符号二进制补码整数,最小值为 -231,最大值为 231-1。 在Java SE 8及以后的版本中,可以使用int数据类型来表示一个无符号的32位整数,最小值为0,最大值为232- 1. 使用Integer 类将int 数据类型用作无符号整数。有关更多信息,请参阅数字类部分。 compareUnsigneddivideUnsigned 等静态方法已添加到 Integer 类中,以支持无符号整数的算术运算。

longlong 数据类型是 64 位二进制补码整数。签名的long 的最小值为-263,最大值为263-1。 在 Java SE 8 及更高版本中,您可以使用 long 数据类型来表示无符号的 64 位 long,其最小值为 0,最大值为 264−1. 当您需要比 int 提供的值范围更广的值时,请使用此数据类型。 Long 类还包含 compareUnsigneddivideUnsigned 等方法,以支持无符号 long 的算术运算。

但是,我找不到声明无符号长整数或整数的方法。例如,以下代码给出了“文字超出范围”的编译器错误消息(当然,我使用的是 Java 8),而它应该在范围内(分配的值恰好是 264 -1):

public class Foo {
    static long values = 18446744073709551615L;
    
    public static void main(String[] args){
        System.out.println(values);
    }  
}

那么,有没有办法声明一个 unsigned int 或 long?

【问题讨论】:

  • Java 8 中的 Long.MAX_VALUE 常量返回什么?
  • 没有无符号整数或无符号长类型。如果您使用其中一种新方法,该方法会将 32 位或 64 位整数视为无符号数。但仅此而已。变量的类型仍然是有符号的,你要记住你将它用作无符号数。他们没有添加无符号文字,但如果有足够多的人对它们进行错误处理,他们可能会将它们添加到 Java 9 中。 :)
  • 除了添加新方法之外,他们并没有真正改变任何东西。
  • 据我所知,他们所做的只是添加可以返回无符号值的方法,但不允许您声明无符号值。如果你问我有点傻,而且真的很痛苦。我想知道是否一种方法是使用 Integer.divideUnsigned,其中一个参数为 1,另一个是您想要视为无符号的任何数字。据我所知,会起作用,但似乎是一种非常愚蠢的做事方式。
  • @ajb 我怎样才能在“窃听”过程中提供任何帮助以最终在 Java 中看到正确的未签名? :)

标签: java java-8 unsigned


【解决方案1】:

嗯,即使在 Java 8 中,longint 仍然是有符号的,只有一些方法将它们视为无符号。如果你想像这样写无符号long 文字,你可以这样做

static long values = Long.parseUnsignedLong("18446744073709551615");

public static void main(String[] args) {
    System.out.println(values); // -1
    System.out.println(Long.toUnsignedString(values)); // 18446744073709551615
}

【讨论】:

  • 我看到的一个观察结果是排序已损坏。如果我要从某个系统(顺便说一下,Twitter 提供这样的 ID)并想要对它们进行排序,也许是因为我知道它们是按时间顺序排列的,那么 Long.MAX_VALUE 之外的所有内容实际上都会在 0 之前显示为负数使用 Java 的实现 :-(。相反,似乎还必须将其向下移动,以便 unsigned 0 映射到有符号的 Long.MIN_VALUE。
  • @DavidSmiley 好点。要对无符号长整数进行排序,请使用Long.compareUnsigned,或将该方法作为比较器传递给排序函数,
【解决方案2】:

根据您发布的文档和this blog post - 在无符号整数/长整数和有符号整数之间声明原语时没有区别。 “新支持”是在 Integer 和 Long 类中添加静态方法,例如Integer.divideUnsigned。如果您不使用这些方法,那么 2^63-1 以上的“无符号”long 只是一个带有负值的普通旧 long。

从快速浏览来看,似乎没有一种方法可以在 +/- 2^31-1 或 +/- 2^63-1 之外的范围内声明整数常量。您必须手动计算与超出范围的正值对应的负值。

【讨论】:

    【解决方案3】:
        // Java 8
        int vInt = Integer.parseUnsignedInt("4294967295");
        System.out.println(vInt); // -1
        String sInt = Integer.toUnsignedString(vInt);
        System.out.println(sInt); // 4294967295
    
        long vLong = Long.parseUnsignedLong("18446744073709551615");
        System.out.println(vLong); // -1
        String sLong = Long.toUnsignedString(vLong);
        System.out.println(sLong); // 18446744073709551615
    
        // Guava 18.0
        int vIntGu = UnsignedInts.parseUnsignedInt(UnsignedInteger.MAX_VALUE.toString());
        System.out.println(vIntGu); // -1
        String sIntGu = UnsignedInts.toString(vIntGu);
        System.out.println(sIntGu); // 4294967295
    
        long vLongGu = UnsignedLongs.parseUnsignedLong("18446744073709551615");
        System.out.println(vLongGu); // -1
        String sLongGu = UnsignedLongs.toString(vLongGu);
        System.out.println(sLongGu); // 18446744073709551615
    
        /**
         Integer - Max range
         Signed: From −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 – 1
         Unsigned: From 0 to 4,294,967,295 which equals 2^32 − 1
    
         Long - Max range
         Signed: From −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, from −(2^63) to 2^63 − 1
         Unsigned: From 0 to 18,446,744,073,709,551,615 which equals 2^64 – 1
         */
    

    【讨论】:

    • 应该添加一些解释,而不仅仅是把代码扔在那里。
    【解决方案4】:

    在 Java 8 或 Java 9 中没有办法声明 unsigned long or int。但有些方法将它们视为未签名,例如:

    static long values = Long.parseUnsignedLong("123456789012345678");
    

    但这不是变量的declaration

    【讨论】:

    • 我为什么不呢。他们可以轻松添加 uint 和 ulong 类型
    • @docesam 在thisthis 文档中有详细解释。简而言之,只是添加了一种对 Integer 类进行无符号操作的方法。如果他们可以轻松添加我不知道他们为什么不这样做;-)
    • @docesam 不,他们不能“轻松添加 uint 和 ulong 类型”。这将需要彻底检查 JLS、JVM 规范、JNI、许多库(如 java.util.Arrays)、反射等等。
    • @Michaelangel007 嘿,我想我们正在以不同的背景假设来处理这个话题。愿意给我发一封电子邮件,我们将讨论细节?
    • @Nayuki 你真的了解有符号右移与无符号右移之间的区别吗?提示:一个符号扩展,另一个零扩展。弄乱代码和掩码(即 & 0x7FFFFFFF)就是这样 - 不必要的混乱,因为在 Java 8 之前,该语言已经脑死了。
    【解决方案5】:

    如果可以选择使用第三方库,则有 jOOUjOOQ 的衍生库),它为 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

    (免责声明:我为这些库背后的公司工作)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-17
      • 2015-06-19
      • 2015-09-01
      • 2011-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多