Java 中单例模式和静态类的区别

此文为译文, 原文在: https://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

译者注:

  • 单例模式:是指实现了单例模式的类。下文提到单例类的时候指的是同一含义。
  • 静态类: 此处的静态类并不是特指语法意义上的静态类,而是指只包含静态方法的类。下文提到的静态类静态静态方法,在本文中的含义是一样的。
  • 另外一篇关于单例模式的不错的文章:http://poltora.info/blog/all-you-want-to-know-about-singleton/

单例模式和静态类都很容易理解, 他们之间有一些相似之处,比如: 他们都可以在不创建新对象的前提下使用,他们都只提供一个实例对象。大体上看, 他们好像都是为了同样的目的而存在。正是因为这种相似点,在面试的时候经常会被问到: 什么情况下需要用单例而不使用静态方法? 或者 你能用静态类(static class)来代替单例模式吗?他们之间有什么区别?。为了回答这两个问题,了解单例模式和静态类之间的本质区别就很重要。单例模式提供给你一个对象,而静态类提供给你静态方法。因为你得到一个对象总比只提供给你一个方法要能做更多的事情,这一点能帮助你做出决定,什么时候应该用单例,而什么时候应该用静态方法。

通过这篇文章,你将会了解到什么情况下使用单例模式比较好,以及什么时候使用静态类会更好一点。在 JDK 中已经有一些关于单例模式和静态类的使用场景,而且他们使用的非常恰当。比如: java.lang.Math 就是一个只包含静态方法的 final class ; 而java.lang.Runtime则是一个单例类的实现。如果你对单例模式或静态类不太熟悉,那么你需要知道的是 静态类是一个只能包含静态方法(而不能包含实例方法)的 Java 类, 一个比较好的例子就是java.lang.Math, 在这个类当中包含了大量的关于数学计算的util方法, 比如sqrt()。 而单例类是那些在整个应用程序中只存在一个实例的类,比如java.lang.Runtime.

什么时候应该用静态类而不是单例

确实存在这样一些场景,用静态类比单例类更合适。一个不错的例子就是java.lang.Math他不是一个单例类, 而是一个全部方法都定义为静态方法的类。下面列出来的是一些我认为使用静态类比单例类更合适的场景。

  1. 如果你的单例类并没有保存任何状态性质的属性,而只是提供了一些公共方法,那么就应该考虑包含静态方法的类,因为 Java 在编译期的静态绑定特性,静态方法比单例类要快很多。但是请记住,在静态类中维护状态并不是一种推荐的做法,尤其是在并发执行的环境中,因为在多线程运行修改静态变量的状态时,如果不能正确地处理线程之间的关系,这可能会导致由于条件竞争而出现莫名其妙的问题。

  2. 另外,当你需要把一系列的 util 方法放到一个类当中时,应该用静态方法;除此之外,当你希望只对外提供一种资源访问的方式,那么就应该使用单例模式。

单例类和静态方法之间的区别

这是我们的第二个关于单例和静态之间关系的问题。我之前说过,他们之间最本质的区别就是,一个代表对象,而另一个代表方法。下面是 Java 当中二者之间的其他不同之处。

  1. 静态类比单例模式的效率更高,因为静态方法在编译期就完成了静态绑定。
  2. 另外一个区别就是,是否支持覆写(override)。因为 Java 中的静态方法是不能被覆写的,这就导致某些情况不够灵活。而你随时可以继承一个非 final 的单例类来覆写其中的方法。
  3. 在做单元测试的时候,静态类比单例类更难被 mock,因此也更难被测试。而单例类很容易被 mock 来执行单元测试。在使用 Junit 的时候,你可以更简单地为构造方法或普通方法传入单例类的 mock 对象来执行测试用例。
  4. 如果你需要维护一些状态信息,那么单例比静态类更合适。因为在静态类中维护状态信息很容易导致细微的 bug 。
  5. 单例对象可以被延迟初始化。而静态类总是在类被加载的时候就初始化。
  6. 很多依赖注入的框架很好的处理了单例对象,比如在 Spring 中实现一个单例对象就很简单。

以上就是关于静态类和单例类之间的区别。了解这些会有助于你决定在何时使用何种方式来完成你的工作。

相较于静态类,单例模式的优点有哪些

单例类最主要的优点就是,单例模式面向对象的特性更强一些。在使用单模式的时候,你可以通过继承来实现多态,也可以通过实现接口来提供同一接口的不同实现。 比如java.lang.Runtime, 他就是一个单例类,当调用 getRuntime() 的时候,不同的 JVM 中可以返回不同的实现对象,同时又可以保证在 JVM 中只存在一份实例。如果我们把java.lang.Runtime定义为一个静态类就不可能实现在不同 JVM 中返回不同实现的行为。

上面就是关于单例类和静态类的区别。当你需要一个具有面向对象特性的类的时候,就用单例模式;而如果你只是把一些静态方法放到一个类中,那就用静态类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容