在Java中声明一个unsigned int


316

有没有一种方法可以在Java中声明一个无符号的int?

或也可以这样构成问题:Java的unsigned等同于什么?

只是为了告诉您上下文,我正在查看Java的实现String.hashcode()。我想测试整数是否为32 unsigned int时发生冲突的可能性。


7
Java中没有未签名的类型。
Andrew Logvinov 2012年

1
这篇文章可能会帮助您stackoverflow.com/a/4449161/778687
tusar 2012年

2
似乎不是AFAICT的一种方式。相关:stackoverflow.com/questions/430346/...
詹姆斯·曼宁

11
这取决于您要达到的目的。在大多数情况下,Java中的所有整数都是带符号的。但是,在一种特定情况下,您可以有符号整数视为无符号整数:可以通过使用>>>operator而不是进行右移而无需扩展符号>>
dasblinkenlight 2012年

Answers:


310

Java没有无符号整数的数据类型。

如果需要存储较大的值,可以定义一个,long而不是一个int

您也可以使用带符号的整数,就好像它是无符号的一样。二进制补码表示法的好处是,对于有符号和无符号整数,大多数操作(例如加法,减法,乘法和左移)在二进制级别上都是相同的。但是,一些操作(除法,右移,比较和转换)是不同的。从Java SE 8开始,Integer该类中的新方法允许您完全使用int数据类型来执行无符号算术

在Java SE 8和更高版本中,可以使用int数据类型表示无符号的32位整数,其最小值为0,最大值为2 ^ 32-1。使用Integer类可将int数据类型用作无符号整数。像静态方法compareUnsigneddivideUnsigned等已被添加到Integer类支持算术运算的无符号整数。

请注意,int变量在声明时仍然是带符号的,但是现在可以通过使用Integer类中的这些方法来进行无符号算术运算。


11
公平地讲,对于许多项目来说,技术要求不是那么严格,您确实可以承担这样“浪费”内存的负担。
Simeon Visser

6
我知道,我也了解Java的初衷。但是例如,智能手机不会占用额外的内存。据我所知,他们通常使用Java。但是,我不想在Java程序员和其他程序员之间展开战争。
托马什Zato -恢复莫妮卡

122
对我来说,这不仅仅是浪费金钱的情况。当您进行一点工作时,unsigned更加容易使用
Cruncher 2013年

24
从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
8bitjunkie 2015年

2
@ 7SpecialGems:我已经更新了答案以包含该信息。话虽如此,不可能声明无符号整数或排除负值,只能使用,int就像通过各种方法将其无符号一样。
Simeon Visser,2015年

70

1
@stas我很难理解其用法,而且无法使用无符号数据类型。从我从网上阅读的各种资料中可以看出,它似乎只是围绕着扩大最大值,而隐性本质上保证了它是一个正数。我的理解正确吗,还是还有其他主要原因?此外,既然IntegerJava 8 中的类允许一个人使用unsigned int,则它只是空间和速度之间的差异(因为在C / C ++中它们是原始的,而在Java中则是整个对象包装器)
Abdul

2
@Abdul-在位级工作(通常是因为您与硬件接口)时,您需要设置值以某种方式运行。即-在11111111之后翻转到00000000等。使用有符号代替无符号可能会破坏CRC计算等。这不是放映停止器,只是浪费时间。
罗恩·K

3
@Lorne K:在Java中,int即使已签名也要翻转。这是C / C ++,未签名会翻转,但是签名会在溢出时导致“未定义行为”。如果“转存”是您唯一关心的问题,则不需要未签名。我想这就是CRC例程等在Java中无需额外努力即可工作的原因。这就是为什么新的API仅添加解析,格式化,比较,除法和余数的原因。无论如何,所有其他操作(即所有位操作)以及加,减,乘等操作都在做正确的事情。
Holger

4
@Ciprian Tomoiaga:为了进行累加,输入和结果的位模式不取决于您将其解释为带符号的数字还是带符号的数字。如果您有耐心,可以尝试使用所有2种组合方式…
Holger

3
@Holger感谢您的解释!确实,这就是为什么我们实际上使用2的补码。我确实尝试 2 ^ 8种组合的方式^^
CiprianTomoiagă17

66

int中的值是带符号的还是无符号的,取决于位的解释方式-Java将位解释为带符号的值(它没有无符号的原语)。

如果您有一个要解释为无符号值的int(例如,从知道包含无符号值的DataInputStream中读取一个int),则可以执行以下操作。

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

请注意,十六进制文字是长文字而不是int文字很重要-因此结尾处是“ l”。


3
对我来说,这是最好的答案...我的数据来自NFC卡UID,它可以有4或8个字节...如果是4个字节,我需要将其强制转换为无符号整数,而我不能请使用ByteBuffer.getLong,因为它不是64位数据。谢谢。
Loudenvier 2014年

为什么需要很长的时间。您不能只做0xFFFFFF并保留int吗?
消失

19

我们需要的无符号数来模拟MySQL的签名TINYINTSMALLINTINTBIGINTjOOQ,这就是为什么我们已经创建了女王,一个简约的图书馆提供的包装类型在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。希望这可以帮助。

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


听起来很方便!感谢您的提及。:)
卢卡斯·索萨



2

也许这就是你的意思?

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语句)进行惰性键入的性能时间损失了千分之一秒。不好。(
整理

5
您真的认为,2 * (long) Integer.MAX_VALUE + 2比这更容易理解0x1_0000_0000L吗?在这方面,为什么不简单return signed & 0xFFFF_FFFFL;
Holger

2

看起来您可以通过在使用值之前对这些值执行“逻辑与”来解决签名问题:

示例(byte[] header[0]值为0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

结果:

Integer -122 = 134

2

这里有很好的答案,但是我看不到按位运算的任何演示。就像Visser(当前接受的答案)所说的那样,Java默认对整数进行符号处理(Java 8具有无符号整数,但我从未使用过它们)。事不宜迟,让我们开始吧...

RFC 868示例

如果您需要向IO写入无符号整数会怎样?实际示例是您要根据RFC 868输出时间时。这需要一个32位,大端无符号整数,该整数对自1900年1月1日12:00 AM以来的秒数进行编码。如何编码?

制作自己的无符号32位整数,如下所示:

声明一个4字节(32位)的字节数组

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

这将初始化数组,请参见Java中字节数组是否初始化为零?。现在,您必须按照大端顺序(或小端顺序,如果要破坏)来用信息填充数组中的每个字节。假设您有一个包含时间的长整数(Java中长整数为64位长)secondsSince1900(其中仅利用了前32位,并且您已经处理了Date引用1970年1月1日12:00 AM的事实),然后您可以使用逻辑与从中提取位,然后将这些位移到以大端顺序将其强制转换为字节时不会忽略的位置(数字)。

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位big-endian整数。是的,long数据类型是带符号的,但是我们忽略了这一事实,因为我们假设secondsSince1900仅使用低32位。由于将long强制转换为一个字节,所有高于2 ^ 7(十六进制的前两位)的位都将被忽略。

参考源:Java网络编程,第4版。


1

刚编写了这段代码,就将“ 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);
                    }

-19

您可以使用Math.abs(number)函数。它返回一个正数。


12
nitpick:如果您通过则不会 MIN_VALUE
丹尼斯·孟

2
@ kyo722我无法想象这将在无符号原语范围内返回正值。
Florian R. Klein

1
nitpick#2:如果您通过,则不会0
genisage
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.