• 2010-03-10

    走进Scala——伴生对象补遗

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/60290522.html

    给《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的实现做了更好的统一,让整个模型更容易理解,是一种更值得推荐的做法。

    分享到:
    引用地址:

    评论

  • 呵呵……
    看不懂……
    不过还是顶一下
    我有想学Python 可是又不知道怎么下手……
  • 确实诡异得很,感觉有点像C/C++里定义private field那种_field形式的的写法,也有点像Java的Inner class编译后的名称。看来2.8与2.7可能是个分水岭,说不准像Python那样,到3.X就换掉一大堆2.X的东西了。变化总是存在,看来是变好还是变坏了,还是需要时间去检验啊。