博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scala单例对象和伴生对象
阅读量:6712 次
发布时间:2019-06-25

本文共 4814 字,大约阅读时间需要 16 分钟。

hot3.png

Scala单例对象和伴生对象

Scala 单例对象

转载时请以超链接形式标明文章原始出处和作者信息及本声明

Singlton是一种为许多人熟知的设计模式,到了Scala这里,它成了语言的一部分,换句换说,我们不必像Java那样费劲的自己实现。下面就是一个Singleton:

object Singleton {  def show = println("I am a singleton")}

(Singleton.scala)

这里,我们用object进行声明,它会创建这个一个类,这个类只有一个实例,名字就叫Singleton。我们可以这样使用它:

Singleton.show

编译一下:

scalac Singleton.scala

不同于类的编译,Singleton编译出两个.class文件:Singleton.class和Singleton$.class。其实,真正称得上是Singleton的类是Singleton$,反编译一下,就可以看出来:

javap -c Singleton$

输出如下:

Compiled from "Singleton.scala"public final class Singleton$ {  public static final Singleton$ MODULE$;  public static {};    Code:       0: new           #2                  // class Singleton$       3: invokespecial #12                 // Method "
":()V       6: return  public void show();    Code:       0: getstatic     #18                 // Field scala/Predef$.MODULE$:Lscala/Predef$;       3: ldc           #20                 // String I am a singleton       5: invokevirtual #24                 // Method scala/Predef$.println:(Ljava/lang/Object;)V       8: return}

其中,MODULE$是这个类唯一的实例,这个实例是在static块创建出来的。所以,Singleton.show这样的语句到了JVM的层面,就会变成这样:

Singleton$.MODULE$.show();

不知道你是否注意到,这个类里根本没有构造函数,换句话说,站在使用者的角度,我们根本就没有机会为这个类创建对象。如果你还不太适应这个没有构造函数的世界,可以参考《Javac背后的故事——空类》。

我们都知道,javac会为没有构造函数的类生成一个缺省的构造函数,所以,在Java代码里,如果我们想实现Singleton必须显式声明出一个private的构造函数。而scalac绕过了javac直接生成字节码,它给出了一个用Java语言无法实现的Singleton方案。

scalac 直接生成字节码

如果说Singleton$是真正的Singleton实现,那么还有个Singleton类是干什么的呢?先来反编译,看看它做了些什么:

Compiled from "Singleton.scala"public final class Singleton {  public static void show();    Code:       0: getstatic     #16                 // Field Singleton$.MODULE$:LSingleton$;       3: invokevirtual #18                 // Method Singleton$.show:()V       6: return}

我们看到了,这里有一个方法里同样有一个show方法,不同与Singleton$里的实现,它是static的,而它几乎是完全的透传,也就是说,这个方法实现是:

public static final void show() {  Singleton$.MODULE$.show();}

这样一来,与Java互操作时,我们只要写Singleton.show()就可以了,不必理会Singleton$.MODULE$.show()这种对Java程序员来说很诡异的写法。不过,这还不是全部。

注:

C:\WorkSpace6-scala\scala-train\src\com\usoft>scalac -version

Scala compiler version 2.11.4 -- Copyright 2002-2013, LAMP/EPFL

===================================

Scala 伴生对象

转载时请以超链接形式标明文章原始出处和作者信息及本声明

准备涉水Scala的Java程序员请注意,Scala里没有static。

在大多数情况下,static真不该是static的。像Scala这样想在面向对象上更进一步的程序设计语言,取消static是一种进取的表现,这样得以保证了其面向对象模型的完整性。好吧,我承认,有时候,我们还是需要类一级的属性和操作的。在Scala里,我们还是有机会的,这便是伴生对象 (Companion Object)的作用。

下面就是一个伴生对象的例子:

object Companion {  def show = println("I am a companion")}class Companion {  def shout = Companion.show}

(Companion.scala)

这个object就是我们所说的伴生对象,如果读过《走进Scala——Singleton》,你会觉得这个伴生对象和Singleton异曲同工,实际上,是这样的。伴生对象本身就是一个Singleton,不同的是,它有一个与之同名的类(这里的class Companion),二者可以相互访问彼此的私有成员。在这里,我们暂且不关心私有成员的相互访问。

编译一下:

scalac Companion.scala

同Singleton一样,我们也得到了两个文件:Companion.class和Companion$.class。我们还可以用javap查看反编译的结果,其中,Companion$.class与之前的Singleton$.class几近相同,这里就省略了。一起来看看Companion.class。

javap -c Companion

输出为:

Compiled from "Companion.scala"public class Companion {  public static void show();    Code:       0: getstatic     #16                 // Field Companion$.MODULE$:LCompanion$;       3: invokevirtual #18                 // Method Companion$.show:()V       6: return  public void shout();    Code:       0: getstatic     #16                 // Field Companion$.MODULE$:LCompanion$;       3: invokevirtual #18                 // Method Companion$.show:()V       6: return  public Companion();    Code:       0: aload_0       1: invokespecial #24                 // Method java/lang/Object."
":()V       4: return}

反编译 Companion$,javap -c Companion$

Compiled from "Companion.scala"public final class Companion$ {  public static final Companion$ MODULE$;  public static {};    Code:       0: new           #2                  // class Companion$       3: invokespecial #12                 // Method "
":()V       6: return  public void show();    Code:       0: getstatic     #18                 // Field scala/Predef$.MODULE$:Lscala/Predef$;       3: ldc           #20                 // String I am a companion       5: invokevirtual #24                 // Method scala/Predef$.println:(Ljava/lang/Object;)V       8: return}

因为有了对应的class,object成了伴生对象。从结果可以看出,伴生对象和它对应的类在字节码层面走到了一起(Companion类)。换句话说,在Scala里面的class和object在Java层面里面合二为一,class里面的成员成了实例成员,object成员成了static成员。我们已经知道,这里的static成员只是一个简单的wrapper,封装了实际的操作。

对应到反编译的代码上,我们看到了与object相关的那个static方法——show。因为要构建Companion的实例,所以,生成的代码里有构造函数。此外,class Companion的实例方法shout在字节码层面上也体现到了Companion类里。

至此,我们已经对伴生对象有了一个基本的了解。在Scala的层面上,我们把分属于类和实例分开放置,从代码的组织而言,会更加清晰。在实现层面上,它们都是按照对象处理的(分别用Companion$和Companion),从而达到了对象模型的统一。

注:

C:\WorkSpace6-scala\scala-train\src\com\usoft>scalac -version

Scala compiler version 2.11.4 -- Copyright 2002-2013, LAMP/EPFL

====================END====================

转载于:https://my.oschina.net/xinxingegeya/blog/398720

你可能感兴趣的文章
ArchSummit微课堂|蘑菇街DevOps实践及心路历程分享
查看>>
随手记统一监控平台Focus设计解析
查看>>
中国平安“豪赌”科技?从产险业务IT变形计聊起
查看>>
RSocket:一个面向反应式应用程序的新型应用网络协议
查看>>
ElasticSearchDsl
查看>>
SciPy达到1.0版本,有了新的治理结构
查看>>
IntelliJ IDEA 2018.3 新版本发布,支持 Java 12及Spring Boot增强等特性
查看>>
Go语言很好很强大,但我有几个问题想吐槽
查看>>
独家!支付宝小程序技术架构全解析
查看>>
微软宣布针对Azure Cosmos DB的多个更新
查看>>
GitHub安全告警检测出了400多万个漏洞
查看>>
如何在Python中使用LightFM构建可扩展的电子商务推荐系统?
查看>>
畅谈云原生(上):云原生应用应该是什么样子?
查看>>
取代ZooKeeper!高并发下的分布式一致性开源组件StateSynchronizer
查看>>
AlloyTouch实现下拉刷新
查看>>
Wiki工具使用感悟
查看>>
云因成本高昂屡被关注,上云的价值是什么?
查看>>
深入探索JVM自动资源管理
查看>>
Go现在接受来自GitHub PR的补丁
查看>>
Sonatype收购Vor Security,扩展对Nexus开源组件的支持
查看>>