英文:
What is the real difference between primitives and wrapper classes in Java
问题
我理解这些内容:
- 包装类创建对象,而原始类型不创建对象。
- 包装类与集合一起使用以表示类型。
- 包装类具有方法并可以保存内存地址/空值,而原始类型保存默认值。
- 原始类型比包装类快,因为没有方法或对象的额外开销。
- 自动装箱和拆箱的工作原理。
- 包装类包装原始类型。
然而,我无法理解原始类型和包装类之间的真正区别。为什么需要创建两种不同的数据持有方式?为什么不重用已经存在的内容呢?
例如,如果包装类在原始类型之前引入,那么为什么我们不使用包装类来代替为类似目的开发完全不同的方式,反之亦然。
英文:
I understand stuff like:
- Wrapper class creates an object and primitive does not create object
- Wrapper classes are used with Collections to represent type
- Wrappers have methods and can hold memory address/null and primitives hold default values
- Primitives are fast compare to wrapper classes as there is no overhead of methods or object
- How auto boxing and unboxing works
- Wrapper class wraps primitive type
However, not able to understand the real difference between primitives and wrapper classes. Why there was a need to create two different ways to hold the data? Why we did not reuse what was already available?
For example, if wrapper classes were introduced before primitives then why we did not use wrapper classes instead of developing altogether a different way for similar purpose and vice versa.
答案1
得分: 7
真正的区别在于 原始类型 不是 引用类型。
在 Java 类型系统中,引用类型有一个共同的根,而原始类型则没有:所有引用类型都是 Object
的子类型。相比之下,原始类型没有共同的根;每种原始类型都是其自己特殊的存在。
这意味着用 Object
类型声明的变量可以保存任何引用类型的值,但不能保存任何原始类型的值。
如果你想创建一些通用的数据结构,这就会成为一个问题。考虑如何实现类似 ArrayList 或 Vector 的“动态数组”数据结构。你可以使用数组 Object[]
来存储元素,这对于所有引用类型都可以工作。但由于原始类型没有共同的根,你必须为每种原始类型创建单独的实现。
为了解决这个问题,包装类被创建出来。现在,不再需要为动态数组创建 8 个单独的实现(1 个用于引用类型,7 个用于原始类型),你可以将每个原始值包装在一个对象中,然后只使用引用类型的实现。
原始类型和包装类是在同一时期创建的,当时设计和实现了 Java 1.0。设计师们没有“重用已有的内容”,因为没有任何内容可用:他们从零开始构建了一切。
设计师们是否可以以其他方式解决这个问题,也许可以通过创建一个对于原始类型和引用类型都有共同根的类型系统?是的,但他们没有这样做,他们可能有很好的原因:实现复杂性、易于理解、上市时间,等等...
英文:
The real difference is that primitive types are not reference types.
In Java type system, reference types have a common root, while primitive types do not: All reference types are subtypes of Object
. In comparison, primitive types do not have a common root; each primitive type is its own special unicorn.
This means that a variable declared with Object
type can hold a value of any reference type, but it cannot hold a value of any primitive type.
This is a problem if you want to create data structures that are generally useful. Consider how you would implement a "dynamic array" data structure like ArrayList or Vector. You could use an array Object[]
to store the elements, and that would work for all reference types. But since primitive types don't have a common root you would have to create a separate implementation for each primitive type.
To solve this problem, wrapper classes were created. Now, instead of needing 8 separate implementations of dynamic array (1 for reference types and 7 for primitive types), you could wrap each primitive value in an object, and just use the implementation for reference types.
Primitive types and wrapper classes were created at the same time, when the first design and implementation of Java 1.0 were made. The designers did not "reuse what was already available" because nothing was available: they built everything from scratch.
Could the designers have solved the problem some other way, maybe by creating a type system that had a common root for both primitive and reference types? Yes, but they didn't, and they probably had good reasons: implementation complexity, ease of understanding, time to market, ...
答案2
得分: 2
实际上,这个问题非常有见地。答案是好的,也是正确的,但我认为值得问的基础问题是:原始类型是否应该存在?当时我们对此进行了很多讨论,我认为事情发展成这样的原因与Oak(后来的Java)是作为物联网(Internet of Things)的嵌入式语言而设计有关。如果它最初是作为服务器语言设计的,可能会非常不同。我认为原始类型是一个传统的概念,实际上对正如Joni提到的那些原因非常有害。系统中的一切都可以扩展为Object是可能的和值得的。
如何消除原始类型?通过更智能的JVM。HotSpot可以在尽可能的地方将特殊的原始对象转换为适当的机器代码,就不需要自动装箱、包装类或类型系统分割的困难了。我认为唯一需要对Integer、Float、Double等类施加的限制是它们必须是final的。这将允许这些类在可能的情况下被优化,就像它们是原始类型一样,但实际上不需要将原始类型纳入语言中。你甚至可以为这些特殊类创建语法缩写,比如'int'、'float'和'double',但重要的是,如果类型系统完全统一,那么它将更好。
但当你考虑智能烤面包机时,你不会开始尝试构建这样的东西。Java在其取得巨大成功方面的发展是纯粹的偶然。它恰好在合适的时间处于解决许多与网络相关的问题的位置。但这并不是计划中的,所以有很多事情是人们希望重新考虑的。我认为Sun/Oracle的许多人在事后会选择消除原始类型。
英文:
Actually, this question is pretty insightful. The answers are good and correct, but the underlying question that I think is worth asking is: should primitive types exist at all? We had a lot of discussion about this at the time and I think the reason things ended up the way they did had to do with the fact that Oak (later Java) was designed as an embedded language for the IOT (internet of things). If it had been originally designed as a server language, it might have been very different. I think primitive types are a legacy idea that is actually very harmful for exactly the reasons that Joni mentions. It's possible and desirable to have everything in the system extend Object.
How could you eliminate primitives? With a smarter JVM. HotSpot could turn special primitive objects into appropriate machine code wherever possible and there wouldn't be a need for autoboxing, wrappers or difficulties with the type system being split. The only limitation that I think would need to be placed on Integer, Float, Double, etc., is that they would have to be final. This would allow these classes to be optimized anywhere possible as if they were primitives without actually having primitives in the language. You could even have syntactic abbreviations like 'int', 'float' and 'double' for these special classes, but the important thing is that the type system would be better if it was fully unified.
But you don't start trying to build such a thing when you're thinking about smart toasters. What happened to Java in terms of its wild success was a pure accident. It happened to be a solution to a lot of web-related issues just sitting there at the right time. But it wasn't planned that way, so there are a lot of things people would like to have back. I think a lot of people at Sun/Oracle would eliminate primitives in hindsight.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论