Java集合仅存储对象,而不存储原始类型。但是我们可以存储包装器类。
为什么会有这种约束?
class
而是由JVM 定义的。该语句int i = 1
定义了一个指向int
JVM 中定义的对象的单例实例的指针,该实例设置为1
JVM中某个位置定义的值。是的,Java语言中的指针-语言实现只是从您那里抽象出来。原始语言不能用作泛型语言,因为该语言断言所有泛型类型都必须是超类型Object
-因此为什么A<?>
要A<Object>
在运行时编译为。
Java集合仅存储对象,而不存储原始类型。但是我们可以存储包装器类。
为什么会有这种约束?
class
而是由JVM 定义的。该语句int i = 1
定义了一个指向int
JVM 中定义的对象的单例实例的指针,该实例设置为1
JVM中某个位置定义的值。是的,Java语言中的指针-语言实现只是从您那里抽象出来。原始语言不能用作泛型语言,因为该语言断言所有泛型类型都必须是超类型Object
-因此为什么A<?>
要A<Object>
在运行时编译为。
Answers:
这是一个Java设计决策,有人认为这是一个错误。容器需要对象,而基元不是从对象派生的。
这是.NET设计人员从JVM中学到的地方,并实现了值类型和泛型,因此在许多情况下都无需装箱。在CLR中,通用容器可以将值类型存储为基础容器结构的一部分。
Java选择在编译器中添加100%的通用支持,而没有JVM的支持。JVM本身就是这样,它不支持“非对象”对象。Java泛型允许您假装没有包装器,但是您仍然要付出拳击的性能代价。这对于某些类的程序很重要。
装箱是一种技术折衷,我认为这是泄漏到语言中的实现细节。自动装箱是不错的语法糖,但仍然会降低性能。如果有的话,我希望编译器在自动装箱时发出警告。(据我所知,现在也许是在2010年,我写了这个答案)。
关于拳击的一个很好的解释:为什么有些语言需要装箱和拆箱?
以及对Java泛型的批评: 为什么有人声称Java的泛型实现不好?
在Java的辩护中,很容易向后看和批评。JVM经受了时间的考验,并且在许多方面都是不错的设计。
Object.ReferenceEquals
型的引用Object
,其识别盒装整数,但它不应该是合法的传递整数值]。Java的自动拆箱很麻烦,恕我直言。
使实施更容易。由于Java原语不被视为对象,因此您需要为每个这些原语创建一个单独的集合类(无需共享模板代码)。
当然,您可以这样做,只需查看GNU Trove,Apache Commons Primitives或HPPC。
除非您有非常大的集合,否则包装程序的开销不足以让人们关心(并且,当您确实有非常大的原始集合时,您可能需要花一些精力来研究使用/构建专门的数据结构) )。
有自动装箱和自动拆箱的概念。如果您尝试将储存在int
中,List<Integer>
则Java编译器会自动将其转换为Integer
。
它不是真正的约束吗?
考虑是否要创建一个存储原始值的集合。您将如何编写一个可以存储int,float或char的集合?最有可能您将获得多个集合,因此您将需要一个intlist和charlist等。
编写收集类时,可以利用Java的面向对象特性,它可以存储任何对象,因此只需要一个收集类。多态这一思想非常有力,并大大简化了库的设计。
我认为我们可能会在基于JEP的Java 10中看到JDK在此领域的进展-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。