为什么Java不支持无符号整数?
在我看来,这是一个奇怪的遗漏,因为它们允许人们编写不太可能在意外的大输入上产生溢出的代码。
此外,使用无符号整数可以是一种自我文档的形式,因为它们表明无符号整型所要保存的值永远不应该是负数。
最后,在某些情况下,无符号整数对于某些运算(如除法)更有效。
包含这些的缺点是什么?
为什么Java不支持无符号整数?
在我看来,这是一个奇怪的遗漏,因为它们允许人们编写不太可能在意外的大输入上产生溢出的代码。
此外,使用无符号整数可以是一种自我文档的形式,因为它们表明无符号整型所要保存的值永远不应该是负数。
最后,在某些情况下,无符号整数对于某些运算(如除法)更有效。
包含这些的缺点是什么?
当前回答
我听说它们将在接近最初的Java发行版时被包含。Oak是Java的前身,在一些规范文档中提到了使用值。不幸的是,这些都没有被引入Java语言。据任何人所知,可能由于时间限制,它们没有得到实施。
其他回答
因为无符号类型是纯粹的邪恶。
事实上,在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。
由于滥用无符号算术而导致的一两个错误之后,人们不得不开始考虑获得的额外比特是否值得额外的麻烦。我正在尽可能地避免在算术中使用无符号类型,尽管仍然将它用于非算术操作,如二进制掩码。
I once took a C++ course with someone on the C++ standards committee who implied that Java made the right decision to avoid having unsigned integers because (1) most programs that use unsigned integers can do just as well with signed integers and this is more natural in terms of how people think, and (2) using unsigned integers results in lots easy to create but difficult to debug issues such as integer arithmetic overflow and losing significant bits when converting between signed and unsigned types. If you mistakenly subtract 1 from 0 using signed integers it often more quickly causes your program to crash and makes it easier to find the bug than if it wraps around to 2^32 - 1, and compilers and static analysis tools and runtime checks have to assume you know what you're doing since you chose to use unsigned arithmetic. Also, negative numbers like -1 can often represent something useful, like a field being ignored/defaulted/unset while if you were using unsigned you'd have to reserve a special value like 2^32 - 1 or something similar.
Long ago, when memory was limited and processors did not automatically operate on 64 bits at once, every bit counted a lot more, so having signed vs unsigned bytes or shorts actually mattered a lot more often and was obviously the right design decision. Today just using a signed int is more than sufficient in almost all regular programming cases, and if your program really needs to use values bigger than 2^31 - 1, you often just want a long anyway. Once you're into the territory of using longs, it's even harder to come up with a reason why you really can't get by with 2^63 - 1 positive integers. Whenever we go to 128 bit processors it'll be even less of an issue.
这是一个古老的问题,pat确实简单地提到了char,我只是想我应该为其他人扩展这个问题,他们将在未来的道路上看到这个问题。让我们仔细看看Java的基本类型:
字节- 8位有符号整数
短16位有符号整数
Int - 32位有符号整数
长64位有符号整数
Char - 16位字符(无符号整数)
虽然char不支持无符号算术,但它本质上可以被视为无符号整数。您必须显式地将算术运算转换回char类型,但它确实提供了一种指定无符号数字的方法。
char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ?
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;
是的,没有对无符号整数的直接支持(显然,如果有直接支持,我就不必将大部分操作转换回char类型)。但是,肯定存在无符号基元数据类型。我也希望看到一个无符号字节,但我猜加倍内存成本,而不是使用char是一个可行的选择。
Edit
JDK8为Long和Integer提供了新的api,在将Long和int值作为无符号值处理时提供了辅助方法。
compareUnsigned divideUnsigned parseUnsignedInt parseUnsignedLong remainderUnsigned toUnsignedLong toUnsignedString
此外,Guava提供了许多帮助器方法来处理整数类型,这有助于弥补由于缺乏对无符号整数的本机支持而留下的空白。
http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html
这个家伙说,因为C标准定义了包含无符号整型和有符号整型的操作被视为无符号整型。这可能导致负符号整数滚动到一个大的无符号整数,可能会导致错误。
我能想到一个不幸的副作用。在java嵌入式数据库中,使用32位id字段可以拥有的id数量是2^31,而不是2^32(~ 20亿,而不是~ 40亿)。