繁体   English   中英

为什么BigInteger不是原始的

[英]Why isn't BigInteger a primitive

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

 i += d + p + y;

对于BigInteger会这样写:

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

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

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

那是因为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 因为它不仅仅是一个例外的运算符。 您需要对运算符*/+-<<^等进行例外处理。 并且你仍然会在对象本身中进行一些操作(比如在Java中没有运算符表示的pow ),对于基元来说,这些操作由专业类(如Math )处理。

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

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

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

可以占用任意大量存储器的BigInteger不能存储在单个REGISTER中,并且需要执行多个指令来进行简单求和。

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM