Scala:获取混合了特征的类的名称
给定一个类的实例,我们显然可以返回其名称:Scala:获取混合了特征的类的名称,scala,traits,Scala,Traits,给定一个类的实例,我们显然可以返回其名称: trait MixedInClassDiscovery { val className = this.getClass.getName } class AClass extends MixedInClassDiscovery { ... this.className // returns "AClass" ... } 但是这种方法使用反射,对AClass的每个实例使用一次反射。是否可以对每堂课做一次同样的操作 想到的一个解决方案是将
trait MixedInClassDiscovery {
val className = this.getClass.getName
}
class AClass extends MixedInClassDiscovery {
...
this.className // returns "AClass"
...
}
但是这种方法使用反射,对AClass
的每个实例使用一次反射。是否可以对每堂课做一次同样的操作
想到的一个解决方案是将它混合到伴随对象中,而不是类本身。您可以使用pimp my lib模式来实现。创建从
AnyRef
到例如ClassNameAdder
的隐式转换。但不建议在类型层次结构的这个级别创建这样的隐式转换
不管怎样,代码来了:
scala> class ClassNameAdder(ref: AnyRef) { def className = ref.getClass.getName }
defined class ClassNameAdder
scala> implicit def anyref2classnameadder(ref: AnyRef) = new ClassNameAdder(ref: AnyRef)
anyref2classnameadder: (ref: AnyRef)ClassNameAdder
scala> "foo".className
res6: java.lang.String = java.lang.String
scala> new Object().className
res7: java.lang.String = java.lang.Object
scala> List(1,2,3).className
res8: java.lang.String = scala.collection.immutable.$colon$colon
scala> class MyClass
defined class MyClass
scala> val myClass = new MyClass
myClass: MyClass = MyClass@1398044
scala> myClass.className
res9: java.lang.String = MyClass
我想不出任何不增加额外开销的方法。但是,您可以使用伴生对象和一些额外的工作:
object Example {
trait Discovery {
def companion: Discovered
def className: String = companion.className
}
trait Discovered extends Discovery {
override lazy val className = {
println("Getting class name!") // To see how many times we're called
this.getClass.getSuperclass.getName
}
}
class Test extends Discovery {
def companion = Test
}
object Test extends Test with Discovered {}
}
在这里我们看到这是可行的:
scala> val a = new Example.Test
a: Example.Test = Example$Test@17e4c97
scala> val b = a.className
Getting class name!
b: String = Example$Test
scala> val c = a.className
c: String = Example$Test
但这需要付出相当大的代价:您不仅需要用发现来装饰类,还需要实现companion方法,并为每个类编写companion对象(顺便说一句,它不需要具有相同的名称)。不,此代码仍然对每个实例进行反射调用。实际上,对于每一个
className
调用,尽管这可以很容易地修复。