Java集合只存储对象,而不是基本类型;但是我们可以存储包装类。
为什么会出现这种限制?
答案 0 :(得分:85)
这是一个Java设计决策,有些人认为是错误的。容器需要对象和基元不是从Object派生的。
这是.NET设计人员从JVM中学到的一个地方,并实现了值类型和泛型,以便在许多情况下消除拳击。在CLR中,通用容器可以将值类型存储为底层容器结构的一部分。
Java选择在没有JVM支持的情况下在编译器中添加100%的泛型支持。 JVM就是这样,不支持“非对象”对象。 Java泛型允许你假装没有包装器,但你仍然支付拳击的性能价格。这对某些类别的程序非常重要。
拳击是一种技术妥协,我觉得这是实施细节泄漏到语言中。 Autoboxing是很好的语法糖,但仍然是性能损失。如果有的话,我希望编译器在自动装箱时警告我。 (据我所知,现在可能,我在2010年写了这个答案)。
关于拳击的一个很好的解释:Why do some languages need Boxing and Unboxing?
批评Java泛型:Why do some claim that Java's implementation of generics is bad?
在Java的辩护中,很容易向后看和批评。 JVM经受住了时间的考验,在很多方面都是一个很好的设计。
答案 1 :(得分:15)
使实施更容易。由于Java基元不被视为对象,因此您需要为每个基元创建单独的集合类(无需共享的模板代码)。
您可以这样做,当然,只需看GNU Trove,Apache Commons Primitives或HPPC。
除非你有非常大的集合,否则包装器的开销对于人们来说并不重要(当你确实拥有非常大的原始集合时,你可能需要花费精力来研究使用/构建专用数据他们的结构)。
答案 2 :(得分:11)
这是两个事实的组合:
int
不是Object
)List<?>
在运行时实际上是List<Object>
)由于这两者都是正确的,因此通用Java集合无法直接存储基元类型。为方便起见,引入了自动装箱以允许原始类型自动装箱作为参考类型。但不要误以为,无论如何,集合仍然存储对象引用。
这可以避免吗?也许
int
是Object
,则根本不需要框类型。答案 3 :(得分:7)
有auto-boxing和自动取消装箱的概念。如果您尝试在int
中存储List<Integer>
,Java编译器会自动将其转换为Integer
。
答案 4 :(得分:3)
这不是一个限制吗?
考虑是否要创建存储原始值的集合。你会如何编写一个可以存储int,float或char的集合?很可能你最终会得到多个集合,所以你需要一个intlist和一个charlist等。
在编写集合类时,利用Java的面向对象特性,它可以存储任何对象,因此您只需要一个集合类。这种多态性的想法非常强大,大大简化了库的设计。
答案 5 :(得分:0)
我认为我们可能会在基于此JEP的Java 10中看到JDK中这个空间的进展 - http://openjdk.java.net/jeps/218。
如果你想在今天的集合中避免装箱原语,那么有几个第三方选择。除了前面提到的第三方选项之外,还有Eclipse Collections,FastUtil和Koloboke。
原始地图的比较也是前不久发布的标题:大型HashMap概述:JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove。 GS Collections(Goldman Sachs)库已迁移到Eclipse Foundation,现在是Eclipse Collections。
答案 6 :(得分:0)
主要原因是Java设计策略。 ++ 1)集合需要对象进行操作,并且基元不是从对象派生的 所以这可能是另一个原因。 2)Java原始数据类型不是ex的引用类型。 int不是对象。
要克服:-
我们有自动装箱和自动拆箱的概念。因此,如果您要存储原始数据类型,编译器会自动将其转换为该原始数据类的对象。