Java 集合只存储对象,而不存储基本类型; 但是我们可以存储包装器类。
为什么会有这种限制?
有 自动装箱和自动拆箱的概念。如果您试图在 List<Integer>中存储 int,Java 编译器将自动将其转换为 Integer。
List<Integer>
int
Integer
这是一个 Java 设计决策,有些人认为这是一个错误。容器希望使用 Object,而原语不从 Object 派生。
这个地方。NET 设计人员从 JVM 中学习并实现了值类型和泛型,这样在许多情况下就不用装箱了。在 CLR 中,泛型容器可以将值类型存储为基础容器结构的一部分。
Java 选择在编译器中添加100% 的通用支持,而不需要 JVM 的支持。JVM 就是这样,不支持“非对象”对象。Java 泛型允许您假装没有包装器,但是您仍然要付出装箱的性能代价。这对于某些类别的程序来说很重要。
拳击是一种技术上的妥协,我觉得它是实现细节渗透到语言中。自动装箱是很好的语法糖,但仍然是一个性能损失。如果有的话,我希望编译器在自动装箱时提醒我。(据我所知,也许是现在,我在2010年写下了这个答案)。
关于拳击的一个很好的解释: 为什么有些语言需要装箱和拆箱?
以及对 Java 泛型的批评: 为什么有些人声称 Java 的泛型实现是不好的?
从 Java 的角度来说,回顾和批评是很容易的。JVM 经受住了时间的考验,在许多方面都是一个好的设计。
它不是一个真正的约束,不是吗?
考虑是否要创建存储基元值的集合。如何编写一个可以存储 int、 float 或 char 的集合?最有可能的情况是,您最终将使用多个集合,因此您将需要一个 intlist 和 charlist 等。
利用 Java 的面向对象特性编写集合类时,它可以存储任何对象,因此您只需要一个集合类。这种多态性思想非常强大,极大地简化了库的设计。
这是两个事实的结合:
Object
List<?>
List<Object>
因为这两个属性都是真实的,所以泛型 Java 集合不能直接存储基元类型。为了方便起见,引入了自动装箱,以允许将基元类型自动装箱为引用类型。尽管如此,毫无疑问,集合仍然存储对象引用。
- 这是可以避免的吗?-也许吧。
使实现更容易。由于 Java 原语不被认为是 Object,因此需要为每个原语创建一个单独的集合类(不需要共享模板代码)。
你可以这样做,当然,只要看到 GNU 宝藏,ApacheCommons 原语或 HPPC。
除非您有非常大的集合,否则包装器的开销不足以让人们关心(当您有非常大的原始集合时,您可能需要花费精力为它们使用/构建一个专门的数据结构)。
我认为我们可以在 JDK 中看到这方面的进展,可能在基于这个 JEP-http://openjdk.java.net/jeps/218的 Java10中看到。
如果您现在想要避免在集合中装箱原语,有几个第三方替代方案。除了前面提到的第三方选择还有 Eclipse 集合,FastUtil和 Koloboke。
不久前还发布了一个关于原始映射的比较,标题是: 大型 HashMap 概览: 京东(JDk)、 FastUtil、高盛(goldmansachs)、 HPPC、 Koloboke、 Trove。GS Collection (Goldman Sachs)图书馆迁移到了 Eclipse基金会,现在是 Eclipse Collection。
其主要原因是 Java 的设计策略。 ++ 1)集合需要对象进行操作,而原语不是从对象派生的 所以这可能是另一个原因。 2) Java 原始数据类型不是引用类型,ex.int 不是对象。
要克服:-
我们有自动装箱和自动拆箱的概念。因此,如果您试图存储基元数据类型,编译器将自动将其转换为该基元数据类的对象。