为什么BigInteger不是原始的

时间:2015-02-26 15:19:21

标签: java biginteger primitive

如果您使用BigInteger(或BigDecimal)并希望对其进行算术运算,则必须使用方法addsubtract。这听起来不错,直到你意识到这一点

 i += d + p + y;
对于BigInteger

会像这样写出来

 i = i.add(d.add(p.add(y)));

正如您所看到的,第一行更容易阅读。这可以解决,如果Java允许运算符重载但它没有,所以这引出了一个问题:

为什么不是BigInteger原始类型,因此它可以利用与其他原始类型相同的运算符?

5 个答案:

答案 0 :(得分:16)

那是因为BigInteger实际上不是任何接近原始的东西。它使用数组和一些其他字段实现,各种操作包括复杂操作。例如,以下是add

的实现
public BigInteger add(BigInteger val) {
    if (val.signum == 0)
        return this;
    if (signum == 0)
        return val;
    if (val.signum == signum)
        return new BigInteger(add(mag, val.mag), signum);

    int cmp = compareMagnitude(val);
    if (cmp == 0)
        return ZERO;
    int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
                       : subtract(val.mag, mag));
    resultMag = trustedStripLeadingZeroInts(resultMag);

    return new BigInteger(resultMag, cmp == signum ? 1 : -1);
}

Java中的基元是通常由主机的CPU直接实现的类型。例如,每台现代计算机都有一个用于整数加法的机器语言指令。因此,它在JVM中也可以有非常简单的字节代码。

BigInteger这样的复杂类型通常不能以这种方式处理,也不能转换为简单的字节代码。它不可能是原始的。


所以你的问题可能是“为什么没有运算符在Java中重载”。嗯,这是语言哲学的一部分。


为什么不像String那样例外?因为它不仅仅是一个例外的运算符。您需要为运营商*/+-<<^等制作例外情况。并且你仍然会在对象本身中有一些操作(比如pow,它不是由Java中的运算符表示),对于基元来说,这些操作由专业类(如Math)处理。

答案 1 :(得分:5)

从根本上说,因为&#34;原始&#34;的非正式含义。它的数据是可以直接使用单个CPU instruction处理的。换句话说,它们是原语,因为它们适合32或64位字,这是CPU使用的数据架构,因此它们可以明确地存储在registers中。

因此您的CPU可以执行以下操作:

ADD REGISTER_3 REGISTER_2 REGISTER_1     ;;; REGISTER_3 = REGISTER_1 + REGISTER_2

可以占用任意大量内存的BigInteger无法存储在单个REGISTER中,需要执行多条指令才能生成简单的总和。

这就是为什么不可能一个原始类型,现在它们实际上是具有方法和字段的对象,比简单的原始类型复杂得多。

注意:我之所以称之为非正式,是因为最终Java设计人员可以定义一个&#34; Java原始类型&#34;作为他们想要的任何东西,他们都拥有这个词,但是这个含义是模糊地使用了这个词。

答案 2 :(得分:2)

intboolean以及char不是原语,因此您可以利用+/等运算符。由于历史原因,它们是原始的,其中最大的是性能。

在Java中,原语被定义为那些不是完全成熟的对象。为什么要创建这些不寻常的结构(然后将它们重新实现为适当的对象,如Integer,稍后)?主要用于性能:对象上的操作比原始类型上的操作慢(并且)。 (正如其他答案所提到的,硬件支持使这些操作更快,但我不同意硬件支持是原语的“基本属性”。)

所以有些类型接受了“特殊处理”(并被实现为原语),而其他类型则没有。可以这样想:即使广受欢迎的String不是原始类型,为什么BigInteger会是?

答案 3 :(得分:1)

这是因为原始类型有大小限制。例如,int是32位,long是64位。因此,如果您创建int类型的变量,JVM会为堆栈分配32位内存。但至于BigInteger,它“理论上”没有大小限制。意思是它的大小可以任意增长。因此,无法知道其大小并在堆栈上为其分配固定的内存块。因此,它被分配在堆上,如果需要,JVM总是可以增加大小。

答案 4 :(得分:0)

原始类型通常是由处理器体系结构定义的历史类型。这就是为什么字节是8位,短是16位,int是32位,长是64位。也许当有更多的128位架构时,会创建一个额外的原语......但我看不出有足够的驱动器...