123
 123

Wed 10 March, 2010

Click here to bookmark this link.Channel Image17:34 走进Scala——伴生对象补遗» 梦想风暴

给《Programming Scala》的作者发邮件澄清一个问题时,我突然意识到之前写的一些关于伴生对象的说法是基于Scala 2.8的讨论。对于现在的稳定版本2.7还是有一些差异的,于是补遗一篇。

还是上篇的那段代码:
object Companion {
  def show = println("I am a companion")
}

class Companion {
  def shout = Companion.show
}
(Companion.scala)

这次,我们用Scala 2.7编译,然后,反编译:

public class Companion extends java.lang.Object implements scala.ScalaObject{
    public Companion();
    public void show();
    public int $tag()       throws java.rmi.RemoteException;
}

我们忽略$tag()。对比于2.8编译出的版本,show()这个static方法不见了。换句话说,使用2.7编译出来的版本,如果我们想访问show()的话,只能这么写:
  Companion$.MODULE$.show();

放心,虽然作为Java程序员,我们不太习惯这种写法,但这确实是一段可以编译运行的Java代码。

Singleton是没有这样的问题,之前所说的内容还是适用的,我们还是可以用static方法的。从这个角度而言,在Scala 2.7里,Singleton和伴生对象的处理是不统一的,而到了2.8,它们就走到了一起。

不过,在伴生对象的处理上,Scala 2.8还有一个小细节需要注意,如果class和object里有同名的方法,则无法生成static方法。也就是说,如果我们把代码改成这样:
object Companion {
  def show = println("I am a companion")
}

class Companion {
  def show = Companion.show
}

再用Scala 2.8反编译,结果就成了:

public class Companion extends java.lang.Object implements scala.ScalaObject{
    public Companion();
    public void show();
}

这也很容易理解,在Java里面,实例方法和static方法也是不能同名的,不信你试试。

Companion$.MODULE$.show(),虽然这样的写法很诡异,但对于Java操作Scala代码来说,这确实屡试不爽的,无论是字节码是用哪个版本Scala编译出来的。但从软件设计的角度而言,Scala 2.8的实现做了更好的统一,让整个模型更容易理解,是一种更值得推荐的做法。






add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Sources