如何在 Java8和 Java9中使用无符号整数?

在 Oracle 的“原始数据类型”呼叫中,它提到 Java8增加了对无符号 int 和 longs 的支持:

int: 默认情况下,int数据类型是一个32位有符号二的补数整数,其最小值为 -231,最大值为231-1。使用 Integer类将 int数据类型用作无符号整数。有关更多信息,请参见“数字类”部分。像 compareUnsigneddivideUnsigned等静态方法已经被添加到 Integer类中,以支持无符号整数的算术运算。

long: long数据类型是一个64位2的补数整数。已签名的 long的最小值为 -263,最大值为263-1。当需要比 int 提供的值范围更大的值时,请使用此数据类型。Long类还包含 compareUnsigneddivideUnsigned等方法,以支持无符号 long的算术运算。

但是,我找不到声明无符号长度或整数的方法。例如,下面的代码给出了一个编译器错误消息“ The Literal is out of range”(当然,我使用的是 Java 8) ,当它应该在 range (赋值精确地为264-1)时:

public class Foo {
static long values = 18446744073709551615L;
    

public static void main(String[] args){
System.out.println(values);
}
}

那么,有没有声明无符号 int 或 long 的方法呢?

129870 次浏览

Per the documentation you posted, and this blog post - there's no difference when declaring the primitive between an unsigned int/long and a signed one. The "new support" is the addition of the static methods in the Integer and Long classes, e.g. Integer.divideUnsigned. If you're not using those methods, your "unsigned" long above 2^63-1 is just a plain old long with a negative value.

From a quick skim, it doesn't look like there's a way to declare integer constants in the range outside of +/- 2^31-1, or +/- 2^63-1 for longs. You would have to manually compute the negative value corresponding to your out-of-range positive value.

Well, even in Java 8, long and int are still signed, only some methods treat them as if they were unsigned. If you want to write unsigned long literal like that, you can do

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


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

There is no way how to declare an unsigned long or int in Java 8 or Java 9. But some methods treat them as if they were unsigned, for example:

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

but this is not declaration of the variable.

    // 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
*/

If using a third party library is an option, there is jOOU (a spin off library from jOOQ), which offers wrapper types for unsigned integer numbers in Java. That's not exactly the same thing as having primitive type (and thus byte code) support for unsigned types, but perhaps it's still good enough for your use-case.

import static org.joou.Unsigned.*;


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

All of these types extend java.lang.Number and can be converted into higher-order primitive types and BigInteger.

(Disclaimer: I work for the company behind these libraries)