为什么Java不支持无符号整数?

在我看来,这是一个奇怪的遗漏,因为它们允许人们编写不太可能在意外的大输入上产生溢出的代码。

此外,使用无符号整数可以是一种自我文档的形式,因为它们表明无符号整型所要保存的值永远不应该是负数。

最后,在某些情况下,无符号整数对于某些运算(如除法)更有效。

包含这些的缺点是什么?


当前回答

我能想到一个不幸的副作用。在java嵌入式数据库中,使用32位id字段可以拥有的id数量是2^31,而不是2^32(~ 20亿,而不是~ 40亿)。

其他回答

恕我直言,原因是他们太懒了,没有去实施/纠正这个错误。 暗示C/ c++程序员不理解unsigned,结构,联合,位标志…太荒谬了。

如果你正在和一个基本的/bash/java程序员交谈,即将开始用C语言编程,没有任何真正的语言知识,或者你只是在说你自己的想法。;)

当你每天处理文件或硬件的格式时,你会开始质疑,他们到底在想什么。

一个很好的例子是尝试使用无符号字节作为自旋转循环。 对于那些不理解最后一句话的人,你究竟是如何称自己为程序员的。

DC

因为无符号类型是纯粹的邪恶。

事实上,在C语言中unsigned int生成unsigned更是邪恶的。

下面是一个让我不止一次头疼的问题的快照:

// We have odd positive number of rays, 
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );

// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
    // Compute the angle between nth ray and the middle one.
    // The index of the middle one is (rays.size() - 1) / 2,
    // the rays are evenly spaced at angle delta, therefore
    // the magnitude of the angle between nth ray and the 
    // middle one is: 
    double angle = delta * fabs( n - (rays.size() - 1) / 2 ); 

    // Do something else ...
}

你注意到这个bug了吗?我承认我是在使用调试器之后才看到它的。

由于n是无符号类型size_t,整个表达式n - (ray .size() - 1) / 2的计算结果为无符号。该表达式旨在表示从中间那条线开始的第n条射线的符号位置:从左边那条线开始的第1条射线的位置为-1,右边那条线的位置为+1,等等。在取abs值并乘以角之后,我将得到第n条射线与中间那条射线之间的夹角。

不幸的是,对我来说,上面的表达式包含了邪恶的unsigned,它的计算结果不是-1,而是2^32-1。随后转换为双密封的bug。

由于滥用无符号算术而导致的一两个错误之后,人们不得不开始考虑获得的额外比特是否值得额外的麻烦。我正在尽可能地避免在算术中使用无符号类型,尽管仍然将它用于非算术操作,如二进制掩码。

你的问题是“为什么Java不支持无符号整数”?

我对你的问题的回答是,Java希望它所有的基本类型:byte, char, short, int和long应该分别被视为字节,word, dword和qword,就像在汇编中一样,Java操作符对所有的基本类型都是有符号的操作,除了char,但只有在char上它们只能是无符号的16位。

因此静态方法对于32位和64位也是无符号操作。

您需要final类,它的静态方法可以用于无符号操作。

你可以创建这个最终类,给它起任何你想要的名字,并实现它的静态方法。

如果你不知道如何实现静态方法,那么这个链接可以帮助你。

在我看来,如果Java既不支持无符号类型,也不支持操作符重载,那么它一点也不类似于c++,所以我认为Java应该被视为与c++和C完全不同的语言。

顺便说一下,这两种语言的名称也完全不同。

所以我不建议在Java中输入类似C的代码也不建议输入类似c++的代码,因为在Java中,你将无法在c++中做你想做的事情,也就是说,代码将不会继续像c++那样,对我来说,这样的代码很糟糕,在中间改变风格。

我建议也为有符号操作编写和使用静态方法,这样就不会在代码中看到有符号和无符号操作混合使用操作符和静态方法,除非在代码中只需要有符号操作,而且只使用操作符是可以的。

此外,我建议避免使用short、int和long基元类型,分别使用word、dword和qword,并且您将调用无符号操作和/或有符号操作的静态方法,而不是使用操作符。

如果您打算只执行有符号的操作,并且只在代码中使用操作符,那么使用这些原语类型short、int和long是可以的。

实际上word, dword和qword在语言中不存在,但你可以为它们创建新类,并且它们的实现应该非常容易:

The class word holds the primitive type short only, the class dword holds the primitive type int only and the class qword holds the primitive type long only. Now all the unsigned and the signed methods as static or not as your choice, you can implement in each class, i.e. all the 16 bit operations both unsigned and signed by giving meaning names on the word class, all the 32 bit operations both unsigned and signed by giving meaning names on the dword class and all the 64 bit operations both unsigned and signed by giving meaning names on the qword class.

如果你不喜欢给每个方法取太多不同的名字,你可以在Java中使用重载,很高兴看到Java没有删除它!

如果您想要8位有符号操作的方法而不是操作符,或者想要8位无符号操作的方法而根本没有操作符,那么您可以创建Byte类(注意,第一个字母'B'是大写的,所以这不是基本类型Byte)并在该类中实现方法。

关于按值传递和按引用传递:

If I am not wrong, like in C#, primitive objects are passed by value naturally, but class objects are passed by reference naturally, so that means that objects of type Byte, word, dword and qword will be passed by reference and not by value by default. I wish Java had struct objects as C# has, so all Byte, word, dword and qword could be implemented to be struct instead of class, so by default they were passed by value and not by reference by default, like any struct object in C#, like the primitive types, are passed by value and not by reference by default, but because that Java is worse than C# and we have to deal with that, then there is only classes and interfaces, that are passed by reference and not by value by default. So if you want to pass Byte, word, dword and qword objects by value and not by reference, like any other class object in Java and also in C#, you will have to simply use the copy constructor and that's it.

这是我能想到的唯一解决办法。我只是希望我可以将原始类型类型定义为word, dword和qword,但Java既不支持typedef,也不支持using,不像c#支持using,这相当于C的typedef。

输出:

对于相同的比特序列,可以以多种方式打印它们:二进制、十进制(就像C printf中%u的含义)、八进制(就像C printf中%o的含义)、十六进制(就像C printf中%x的含义)和整数(就像C printf中%d的含义)。

请注意,C printf不知道作为参数传递给函数的变量的类型,因此printf只知道传递给函数第一个形参的char*对象中的每个变量的类型。

所以在每一个类:Byte, word, dword和qword中,你可以实现print方法并获得printf的功能,即使类的基本类型是有符号的,你仍然可以通过遵循一些涉及逻辑和移位操作的算法将其作为无符号打印到输出中。

不幸的是,我给你的链接没有显示如何实现这些打印方法,但我相信你可以谷歌的算法,你需要实现这些打印方法。

这就是我所能回答你的问题并建议你的。

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

这个家伙说,因为C标准定义了包含无符号整型和有符号整型的操作被视为无符号整型。这可能导致负符号整数滚动到一个大的无符号整数,可能会导致错误。

我知道这个帖子太老了;但是,在Java 8及以后版本中,您可以使用int数据类型来表示无符号32位整数,其最小值为0,最大值为232−1。使用Integer类使用int数据类型作为无符号整数,并且像compareUnsigned(), divideUnsigned()等静态方法已经添加到Integer类中,以支持无符号整数的算术操作。