Java集合只能存储对象,而不能存储基本类型;但是我们可以存储包装类。
为什么有这个限制?
Java集合只能存储对象,而不能存储基本类型;但是我们可以存储包装类。
为什么有这个限制?
这是Java设计时的一个决定,有些人认为这是一个错误。容器需要对象,而原始类型不派生自Object。
这是.NET设计师从JVM学到的一点,并实现了值类型和泛型,从而在许多情况下消除了装箱。在CLR中,通用容器可以将值类型存储为底层容器结构的一部分。
Java选择在编译器中100%添加通用支持,但没有得到JVM的支持。由于JVM的特性,不支持“非对象”对象。Java泛型允许您假装没有包装器,但您仍然要支付装箱的性能代价。对于某些类别的程序来说,这很重要。
装箱是一种技术妥协,我认为它是实现细节泄漏到语言中。自动装箱是一种不错的语法糖,但仍然会导致性能损失。如果可能的话,我希望编译器在自动装箱时警告我。(我不知道,也许现在已经有了,我在2010年写了这篇答案)。
关于装箱的一个好的解释:
为什么一些语言需要装箱和拆箱?以及对Java泛型的批评:为什么一些人认为Java的泛型实现很糟糕?
为了捍卫Java,倒退回去批评很容易。JVM已经经受住了时间的考验,在许多方面都是一个好的设计。
这是两个事实的结合:
int
不是 Object
)。List<?>
实际上是一个 List<Object>
)。由于这两个事实都是真实存在的,泛型 Java 集合不能直接存储基本类型。为了方便起见,自动装箱被引入以允许将基本类型自动转换为引用类型。不过,无论如何,集合仍然存储对象引用。
这可以避免吗?或许可以。
int
是Object
,则根本不需要包装类型。有一个叫做自动装箱和自动拆箱的概念。如果你试图将一个int
存储在List<Integer>
中,Java编译器会自动将其转换为Integer
。
这不算一个限制,对吧?
考虑一下,如果你想创建一个存储基本值类型的集合,你会怎么写一个可以存储int、float或char的集合呢?最有可能的是你需要多个集合,比如intlist和charlist等。
利用Java面向对象的特性,当你编写一个集合类时,它可以存储任何对象,所以你只需要一个集合类。这个想法,即多态性,非常强大,极大地简化了库的设计。
我认为我们可能会在JDK中看到这个领域的进展,可能是在Java 10中,基于这个JEP - http://openjdk.java.net/jeps/218。
如果你想避免在集合中装箱原始类型,现在有几个第三方选择。除了之前提到的第三方选项外,还有Eclipse Collections, FastUtil和Koloboke。
关于原始类型映射的比较也在一段时间前发布,标题为:大型HashMap概述:JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove。GS Collections(Goldman Sachs)库已迁移到Eclipse基金会,现在是Eclipse Collections。