Приведенный пример класса, мы можем, очевидно, возвратить его имя:
trait MixedInClassDiscovery {
val className = this.getClass.getName
}
class AClass extends MixedInClassDiscovery {
...
this.className // returns "AClass"
...
}
Но этот путь использует отражение, однажды для каждого экземпляра AClass
. То же может быть сделано однажды для каждого класса, вместо этого?
Одно решение, которое приходит на ум, состоит в том, чтобы смешаться, оно в компаньона возражает вместо самих классов.
Я не могу придумать, как это сделать без лишних накладных расходов. Однако вы могли бы сделать это с сопутствующими объектами и с парочкой дополнительных работ:
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
, но за это приходится платить: вам нужно не только украсить класс с помощью Discovery, но также реализуйте сопутствующий метод и напишите сопутствующий объект (который, кстати, не обязательно должен иметь одно и то же имя) для каждого класса.
Вы можете сделать это с помощью шаблона 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