如何在Scala混入的Trait B中获取实例化的具体类名称
当然可以实现!
在Scala的特质B内部,完全可以获取到它被实例化时所属的具体类(也就是你的例子里的C)。核心思路是利用运行时类信息,不过需要注意Scala混入特质时的类合成机制,下面给你两种可行的实现方式:
方法一:直接处理合成类的名称
Scala在将特质混入类时,会生成一个带后缀的合成类(比如C$B$1),我们可以通过字符串处理提取原始类名:
trait A { def foo(): Unit } trait B extends A { abstract override def foo(): Unit = { // 提取具体类名称:去掉$及后面的所有内容 val concreteClassName = this.getClass.getSimpleName.replaceAll("\\$.*", "") println(s"当前实例所属的具体类:$concreteClassName") super.foo() } } class C extends A { def foo() = { println("C::foo()") } } val c = new C with B c.foo()
运行这段代码会输出:
当前实例所属的具体类:C C::foo()
方法二:遍历继承链找最底层的具体类
如果存在多层特质混入的场景,方法一的字符串处理可能不够可靠,这时可以通过遍历类的继承关系,找到第一个非特质的类:
trait A { def foo(): Unit } trait B extends A { // 工具方法:递归查找具体类 private def findConcreteClass(clazz: Class[_]): Class[_] = { if (clazz.isTrait) findConcreteClass(clazz.getSuperclass) else clazz } abstract override def foo(): Unit = { val concreteClass = findConcreteClass(this.getClass) println(s"当前实例所属的具体类:${concreteClass.getSimpleName}") super.foo() } } class C extends A { def foo() = { println("C::foo()") } } val c = new C with B c.foo()
这种方式更鲁棒,不管有多少层特质混入,都能准确找到最原始的具体类。
原理说明
当你执行new C with B时,Scala编译器会动态生成一个合成子类,这个类继承自C并实现了特质B。所以this.getClass拿到的是这个合成类的Class对象,但我们可以通过上述两种方式,从合成类追溯到真正的具体类C。
内容的提问来源于stack exchange,提问作者user79074
相关产品推荐
相关产品推荐

