Java 中的基元和包装器 类 之间的真正区别是什么

What is the real difference between primitives and wrapper classes in Java

我理解以下内容:

  1. Wrapper class 创建一个对象而 primitive 不创建对象
  2. Wrapper classes 与 Collections 一起使用来表示类型
  3. 包装器有方法并且可以保存内存address/null,基元保存默认值
  4. 与包装器 classes 相比,原语更快,因为没有方法或对象的开销
  5. 自动装箱和拆箱的工作原理
  6. Wrapper class 包装基本类型

但是,无法理解原语和包装器 classes 之间的真正区别。为什么需要创建两种不同的方式来保存数据?为什么我们不重用已经可用的东西? 例如,如果包装器 classes 在原语之前引入,那么为什么我们不使用包装器 classes 而不是为类似目的开发完全不同的方式,反之亦然。

真正的区别在于基本类型不是引用类型

在 Java 类型系统中,引用类型有一个共同的根,而基本类型没有:所有引用类型都是 Object 的子类型。相比之下,基本类型没有共同的根;每个原始类型都是它自己的特殊独角兽。

这意味着用Object类型声明的变量可以保存任何引用类型的值,但不能保存任何基本类型的值。

如果您想创建通常有用的数据结构,这就是一个问题。考虑如何实现像 ArrayList 或 Vector 这样的“动态数组”数据结构。您可以使用数组 Object[] 来存储元素,这适用于所有引用类型。但是由于基本类型没有共同的根,您必须为每个基本类型创建一个单独的实现。

为了解决这个问题,创建了包装器 类。现在,不需要 8 个单独的动态数组实现(1 个用于引用类型,7 个用于原始类型),您可以将每个原始值包装在一个对象中,然后只使用引用类型的实现。

当 Java 1.0 的第一个设计和实现完成时,原始类型和包装器 类 同时创建。设计师没有“重复使用已经可用的东西”,因为没有可用的东西:他们从头开始构建所有东西。

设计者是否可以通过其他方式解决问题,也许是通过创建一个类型系统,使原始类型和引用类型具有共同的根?是的,但他们没有,他们可能有充分的理由:实施复杂性、易于理解、上市时间……

其实这个问题挺有见地的。答案很好而且正确,但我认为值得一问的根本问题是:原始类型是否应该存在?当时我们对此进行了很多讨论,我认为事情之所以会变成这样,是因为 Oak(后来的 Java)被设计为 IOT(互联网)的嵌入式语言东西的)。如果它最初被设计为一种服务器语言,它可能会大不相同。我认为原始类型是一个遗留的想法,由于 Joni 提到的原因,它实际上是非常有害的。让系统中的所有内容都扩展 Object 是可能的,也是可取的。

你怎么能消除基元?使用更智能的 JVM。 HotSpot 可以尽可能将特殊的原始对象转换为适当的机器代码,并且不需要自动装箱、包装​​器或类型系统被拆分的困难。我认为需要对 Integer、Float、Double 等施加的唯一限制是它们必须是最终的。这将允许这些 类 在任何可能的地方被优化,就好像它们是原语一样,而实际上语言中没有原语。对于这些特殊的 类,您甚至可以使用 'int'、'float' 和 'double' 等句法缩写,但重要的是,如果完全统一,类型系统会更好.

但是当您考虑智能烤面包机时,您不会开始尝试构建这样的东西。 Java 的巨大成功纯属意外。它恰好是许多 web-related 问题的解决方案,只是在正确的时间坐在那里。但它不是那样计划的,所以有很多东西人们想要回来。我认为 Sun/Oracle 的很多人事后都会消除原语。