6

给定一个类的实例,我们显然可以返回它的名称:

trait MixedInClassDiscovery {
  val className = this.getClass.getName
}

class AClass extends MixedInClassDiscovery {
  ...
  this.className // returns "AClass"
  ...
}

但是这种方式使用反射,对于AClass. 可以为每个班级做一次同样的事情吗?

想到的一种解决方案是将其混合到伴随对象而不是类本身中。

4

2 回答 2

1

我想不出任何没有额外开销的方法。但是,您可以使用伴随对象以及一些额外的工作来做到这一点:

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 装饰类,还需要实现伴生方法并为每个类编写伴生对象(顺便说一下,它不必具有相同的名称)。

于 2010-05-12T14:44:54.900 回答
1

你可以用 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
于 2010-05-12T13:57:08.880 回答