为什么Java Collections不能直接存储Primitives类型?

Jav*_*ser 117 java collections types primitive-types

Java集合只存储对象,而不是基本类型; 但是我们可以存储包装类.

为什么这个约束?

cod*_*eim 89

这是一个Java设计决策,有些人认为是错误的.容器需要对象和基元不是从Object派生的.

这是.NET设计人员从JVM学到的一个地方,并实现了值类型和泛型,以便在许多情况下消除拳击.在CLR中,通用容器可以将值类型存储为底层容器结构的一部分.

Java选择在没有JVM支持的情况下在编译器中100%添加泛型支持.JVM就是这样,不支持"非对象"对象.Java泛型允许你假装没有包装器,但你仍然支付拳击的性能价格.这对于某些类程序来说非常重要.

拳击是一种技术妥协,我觉得这是实施细节渗透到语言中.Autoboxing是很好的语法糖,但仍然是性能损失.如果有的话,我希望编译器在自动装箱时警告我.(据我所知,现在可能,我在2010年写了这个答案).

关于拳击的一个很好的解释:为什么有些语言需要拳击和拆箱?

对Java泛型的批评: 为什么有人声称Java的泛型实现很糟糕?

在Java的辩护中,很容易回顾和批评.JVM经受住了时间的考验,在很多方面都是一个很好的设计.

  • 这足以让.NET从中学到并从一开始就实现了自动装箱,并且虚拟机级别的泛型没有装箱费用.Java自己的纠正尝试只是一种语法级别的解决方案,仍然受到自动装箱与无拳击的性能损失的影响.Java的实现表明大型数据结构的性能很差. (12认同)
  • 这不是一个错误,一个经过仔细选择的权衡,我相信它确实为Java提供了很好的服务. (6认同)
  • @mrjoltcola:恕我直言,默认的自动装箱是一个错误,但应该有一种方法来标记变量和参数,这些变量和参数应该自动包装给它们的值.即使是现在,我认为应该添加一种方法来指定某些变量或参数应该*不接受新的自动框值[例如,传递`Object.ReferenceEquals`类型为`Object`的引用应该是合法的盒装整数,但传递整数值不合法].Java的自动拆箱是恕我直言,只是讨厌. (2认同)

Thi*_*ilo 17

使实施更容易.由于Java基元不被视为对象,因此您需要为每个基元创建单独的集合类(无需共享的模板代码).

你可以这样做,当然,只需看看GNU Trove,Apache Commons PrimitivesHPPC.

除非你有非常大的集合,否则包装器的开销对于人们来说并不重要(当你确实拥有非常大的原始集合时,你可能需要花费精力来研究为它们使用/构建专门的数据结构).


pol*_*nts 11

这是两个事实的组合:

  • Java原始类型不是引用类型(例如,int不是一个Object)
  • Java使用类型擦除引用类型做泛型(例如,a List<?>实际上是List<Object>在运行时)

由于这两者都是正确的,因此通用Java集合无法直接存储基本类型.为方便起见,引入了自动装箱以允许原始类型自动装箱作为参考类型.不过不要误会,集合仍然存储对象引用,无论如何.

这可以避免吗?也许.

  • 如果a int是a Object,则根本不需要盒子类型.
  • 如果没有使用类型擦除来完成泛型,那么原语可以用于类型参数.


Jer*_*emy 7

自动装箱和自动拆箱的概念.如果你试图存储一个intList<Integer>Java编译器会自动将其转换为Integer.

  • 我的观点是指出语法和性能之间的区别很重要.我也认为我的意见是事实分享,而不是争论.谢谢. (3认同)