因此在Java中,我们看到原始类型占用的内存空间少于它们的对象。例如,int
占用的空间比Integer
的实例少。
出于这个原因,char
代替String
来存储单个字符通常更为明智。
我想了解这是如何转化为Scala的。
没有基元。我们所拥有的只是AnyVal
或AnyRef
的实例。
每个内存分配之间是否存在差异?
答案 0 :(得分:3)
当然有些原始人。斯卡拉只是(故意)试图隐藏差异。
实际上有4个案例,而不是2个案例:
扩展AnyRef
的类。它们只是通常的Java风格的类,并且具有相同的内存使用。
Unit
。它对应于Java void
,因此通常根本不在运行时表示。如果是,则使用BoxedUnit
类。
Int
,Boolean
等。虽然它们看起来像Scala代码的类,但它们通常表示为JVM原语。但是在某些情况下它们不能用,而是使用盒装类型(Integer
等)。也就是说,当它们是Array
的的泛型类型/方法的参数时。
用户定义的值类。请参阅Yuval Itzchakov的答案。当然,如果你有一个包含一个原语的值类,它最终会被表示为一个原语本身。请注意,它们不是始终在运行时作为基础类型表示,特别是Array[ValueClass]
失败,与案例3相反。
答案 1 :(得分:2)
每个
的内存分配是否有差异
AnyRef
类似于inherting object
,由于标题,每个对象分别为x86 / x64获得8/16字节的正常开销。
AnyVal
允许优化一个非常具体的用例,其中有一个val
参数,该参数包含在class
中,您可以将所述类表示为底层运行时的值,而不是分配类的实例。
AnyVal
有几个限制:
- 必须只有一个主构造函数,其中只有一个public,val参数,其类型不是值类。 (来自Scala 2.11.0 ,. 参数可能是非公开的。)
- 可能没有专门的类型参数。
- 可能没有嵌套或本地类,特征或对象
- 可能无法定义equals或hashCode方法。
- 必须是顶级类或静态可访问对象的成员
- 只能将defs作为成员。特别是,它不能将lazy vals,vars或val作为成员。
- 不能由其他班级延长。
醇>
例如,如果我们采用示例from the documentation:
class Wrapper(val underlying: Int) extends AnyVal {
def foo: Wrapper = new Wrapper(underlying * 19)
}
编译时Wrapper
的表示仍然是一个类。但在运行时,基础表示将是Int
,而不是具有额外Wrapper
字段的类Int
。
但并不总能保证Wrapper
在运行时会成为Int
表示。它不会在以下时间:
答案 2 :(得分:1)
在 Scala 中, Scala 在编译时使用框/ unbox BoxesRunTime.java来处理基本类型:
字节代码:
def foo[T](v: T) = v.toString
def bar(i: Int)= foo(i)
:javap -c bar
public java.lang.String bar(int);
Code:
0: getstatic #19 // Field .MODULE$:L;
3: iload_1
4: invokestatic #25 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
7: invokevirtual #29 // Method .foo:(Ljava/lang/Object;)Ljava/lang/String;
10: areturn
在bar
方法的上述字节代码中,它将原始int类型加到 Int引用类型。这是因为我们使用原始类型int
来表示泛型T
。
字节代码:
def foo(i: Int) = i
def bar[T](i: T) = foo(i.asInstanceOf[Int])
public <T> int bar(T);
Code:
0: getstatic #19 // Field .MODULE$:L;
3: aload_1
4: invokestatic #24 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
7: invokevirtual #28 // Method .foo:(I)I
在bar方法的上述字节代码中,我们将引用类型解析为原始Int类型,因此需要将其解包为基本类型int < /强>
所以在运行时,总是有用于类型解析的box或unbox。它可能会导致性能不佳并消耗更多内存。但我们可以通过以下方式避免它:
它们都用于解决 scala 中的 box / unbox 问题。