为什么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。