java扩展AnyVal和AnyRef的对象的内存分配有什么不同
因此,在Java中,我们看到基本类型比对象类型占用更少的内存空间。例如int
比Integer
的实例占用更少的空间。
出于这个原因,通常更明智的做法是char
而不是String
存储单个字符
我想了解这是如何转化为Scala的。
没有原语。我们所拥有的只是AnyVal
或AnyRef
的实例。
每个内存分配之间是否存在差异
你可以在下面搜索框中键入要查询的问题!
因此,在Java中,我们看到基本类型比对象类型占用更少的内存空间。例如int
比Integer
的实例占用更少的空间。
出于这个原因,通常更明智的做法是char
而不是String
存储单个字符
我想了解这是如何转化为Scala的。
没有原语。我们所拥有的只是AnyVal
或AnyRef
的实例。
每个内存分配之间是否存在差异
# 1 楼答案
在Scala中,Scala在编译时使用box/unboxBoxesRunTime.java处理原语类型:
字节码:
在上述
bar
方法中的字节码中,它将框原语int-type转换为int-reference-type。这是因为我们将原语类型int
用于泛型T
字节码:
在上面的bar方法字节码中,我们正在将一个引用类型解析为基元Int类型,因此需要将其解装箱为基元Int类型
因此,在运行时中,始终存在用于类型解析的box或unbox。它可能会导致性能下降并消耗更多内存。但我们可以通过以下方式避免:
它们都用于解决scala中的box/unbox问题
# 2 楼答案
AnyRef
与插入object
类似,在插入object
时,由于头的原因,每个对象的x86/x64的正常开销分别为8/16字节Scala中的
AnyVal
允许优化一个非常特定的用例,其中您有一个val
参数,它被包装在class
中,并且您可以在运行时将所述类表示为基础值,而不是分配类的实例AnyVal
有几个限制:例如,如果我们以from the documentation为例:
Wrapper
在编译时的表示仍然是一个类。但是在运行时,底层表示将是一个Int
,而不是一个带有额外Int
字段的类Wrapper
但并不总是保证
Wrapper
在运行时会成为Int
表示。当:# 3 楼答案
当然,实际上有原语。Scala只是(有意)试图隐藏差异
实际上有4个案例,而不是2个:
扩展
AnyRef
的类。它们只是普通的Java风格的类,具有相同的内存使用Unit
。它对应于Javavoid
,因此通常根本不在运行时表示。如果是,则使用BoxedUnit
类Int
、Boolean
等等。虽然它们看起来像Scala代码中的类,但它们通常表示为JVM原语。但在某些情况下,它们不能被使用,而是使用装箱类型(Integer
,等等)。也就是说,当它们是泛型类型/方法的参数时,除了Array
的用户定义的值类。见尤瓦尔·伊扎科夫的答案。当然,如果有一个值类包装一个原语,那么它最终会被表示为一个原语本身。请注意,它们在运行时并不总是表示为底层类型,特别是对于
Array[ValueClass]
,与案例3相反