scala中的类型擦除和继承

scala中的类型擦除和继承,scala,inheritance,type-erasure,Scala,Inheritance,Type Erasure,我有下面的类层次结构 trait Item {val id: String} case class MItem(override val id: String, val name: String) extends Item class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) val d = new DItem("1", "one"

我有下面的类层次结构

trait Item {val id: String}

case class MItem(override val id: String, val name: String) extends Item

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name)

val d = new DItem("1", "one", "another one")
println(d)
预期产量

DItem(1, one, another one)
实际产量

Mitem(1,one)

为什么会发生这种情况。建议使用什么,以便获得对象的真实类型和超类的非类型

这不是类型擦除。您之所以得到这个结果,是因为
DItem
Mitem
继承了
toString()
实现。你必须覆盖它才能得到你想要的

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}
结果如下:

scala> val d = new DItem("1", "one", "another one")
d: DItem = DItem(1, one, another one)

scala> println(d)
DItem(1, one, another one)

从case类继承几乎总是一个坏主意,因为除了
toString
继承类之外

另一个缺点是此类后续类的模式匹配有限,即不可能在
case
分支中使用此类类,并可能导致混淆错误

例子 您可能期望此代码中没有错误,但您将得到

<console>:17: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
     case A(id) => println(id)
          ^

所以。。。从case类继承非常容易出错和混淆,除非您知道自己在做什么,否则应该避免使用。

据我所知,从case类继承是不推荐的。所以case类只能从常规类继承

执行println通常会调用传递给它的对象上的toString

因此,在您的代码上发生的是,它将调用对象的toString实现,恰好是具有此实现的MItem

因此,您需要像这样覆盖数据项上的toString:

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}
如果只想获取对象的类型,可以使用getClass

println(d.getClass)

我认为提到这一点会增加答案。@YuvalItzchakov完全同意。我将扩展我的回答,我认为“除非你知道你在做什么”意味着不从case类继承。
class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}
println(d.getClass)