为什么Java集合不能直接存储基元types?
Java集合只存储对象,而不是原始types; 但是我们可以存储包装类。
为什么这个约束?
这是一个Javadevise决策,有人认为是一个错误。 容器需要对象和原语不从Object派生。
这是.NETdevise人员从JVM中学到的一个地方,它实现了值types和generics,使得在很多情况下删除了装箱。 在CLR中,通用容器可以将值types存储为基础容器结构的一部分。
Java在没有JVM支持的情况下,select在编译器中增加100%的通用支持。 JVM就是它,不支持“非对象”对象。 Javagenerics允许你假装没有包装,但你仍然支付拳击的性能价格。 这对于某些类别的程序是重要的。
拳击是一种技术上的妥协,我觉得这是渗透到语言中的实现细节。 Autoboxing是很好的语法糖,但仍然是一个性能损失。 如果有的话,我希望编译器在自动装箱时提醒我。 (据我所知,现在可能,我在2010年写了这个答案)。
关于拳击的一个很好的解释: 为什么有些语言需要拳击和拆箱?
对Javagenerics的批评: 为什么有人声称Java的generics实现不好?
在Java的防守中,很容易回头批评。 JVM经受住了时间的考验,在很多方面都是很好的devise。
使执行更容易。 由于Java原语不被视为对象,因此您需要为每个原语创build一个单独的集合类(无需共享模板代码)。
你可以做到这一点,当然,只要看到GNU Trove , Apache Commons Primitives或HPPC 。
除非你有非常大的集合,否则这些包装的开销并不足以让人们关心(当你真的有很大的原始集合的时候,你可能需要花费精力来为他们使用/构build一个专门的数据结构)。
这是两个事实的结合:
- Java原始types不是引用types(例如,
int
不是Object
) - Java使用引用types的types擦除来实现generics(例如,
List<?>
List<Object>
在运行时确实是一个List<Object>
)
由于这两个都是真的,通用Java集合不能直接存储基本types。 为方便起见,引入了自动装箱function,可以将原始types自动装箱为引用types。 尽pipe如此,集合仍然存储对象引用,无论如何。
这可以避免吗? 也许。
- 如果
int
是一个Object
,那么根本就不需要boxtypes。 - 如果generics没有使用types擦除来完成,那么原语可以用于types参数。
有自动装箱和自动拆箱的概念。 如果您尝试在List<Integer>
存储int
,则Java编译器将自动将其转换为Integer
。
它不是一个约束吗?
考虑如果你想创build一个存储原始值的集合。 你将如何写一个可以存储int,float或char的集合? 最有可能你会得到多个集合,所以你将需要一个intlist和charlist等。
在编写集合类时,利用Java的面向对象特性,可以存储任何对象,因此只需要一个集合类。 这个想法,多态,是非常强大的,大大简化了图书馆的devise。
我想我们可能会在JDK的JDK的这个领域看到进步,可能是基于这个JEP – http://openjdk.java.net/jeps/218 。
如果你想避免在今天收集拳击原语,有几个第三方的替代品。 除了前面提到的第三方选项,还有Eclipse Collections , FastUtil和Koloboke 。
原始地图的比较也在不久前发布,标题如下:Large HashMap概述: JDK,FastUtil,Goldman Sachs,HPPC,Koloboke,Trove 。 GS Collections(Goldman Sachs)图书馆已经迁移到Eclipse Foundation,现在是Eclipse Collections。