软件设计模式之单例模式(JAVA)
什么是单例模式?
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式的特点:
1、单例类有且只能有一个实例。
2、单例类需要自己创建一个自己的实例。
3、单例类需要为其他类提供这个实例。
哪些地方经常用到单例?
在计算机系统中,配置文件,线程池,缓存,日志对象,打印机等经常用到单例模式
所谓“一山不容二虎”,如果出现二虎很容易会出问题,比如配置文件,它终究只是一个文件,如果同时有好几个实例访问它并执行修改操作,那么这时候就会引发出一系列的问题
单例相对于多实例对象也更节约系统资源
单例模式常用的有几种模式?
一般来讲单例模式有三种,分别是:懒汉式,饿汉式,登记式。
下面直接上代码说明吧
①一个类之所以能够创建出实例是因为有构造方法的存在,只要我们把构造方法的访问修饰符改成私有(private),外界就不能通过new来创建该类的实例。
②在单例类中自身new出一个对象,因为要被外界访问,我们可以把它静态化(static),以便外界访问(类型.对象)。
③有时候我们需要控制这个对象,也处于安全起见,我们可以把继续私有化(private),然后提供一个getter方法以便外界访问。
SimpletonDemo1.java(单例类)
package com.lcw.simpleton;
public class SimpletonDemo1 {
//将构造方法私有化,阻止外界直接创建对象
private SimpletonDemo1() {
}
//提供static以便外界访问
private static SimpletonDemo1 instance = new SimpletonDemo1();
//提供getter方法以便外界访问私有化对象,static SimpleDemo1返回类型
public static SimpletonDemo1 getInstance() {
return instance;
}
}
SimpletonTest.java(测试类)
package com.lcw.simpleton;
public class SimpletonTest {
public static void main(String[] args) {
SimpletonDemo1 s1=SimpletonDemo1.getInstance();
SimpletonDemo1 s2=SimpletonDemo1.getInstance();
if(s1==s2){//检测对象的内存地址是否一致
System.out.println("s1和s2是同个对象");
}else{
System.out.println("s1和s2不是同个对象");
}
}
}
效果如下:

上面所说的就是单例模式里饿汉模式,为什么叫饿汉模式呢?
由于这个实例是被static所修饰,被static修饰的成员属于类所有,当类加载的时候,这个成员就被加载了,也就是说不管外界是否调用这个类,它都已经被加载了。
看起来好像是饿汉,不管三七二十一,先吃了你再说。
下面再来看下单例模式中的懒汉模式
就字面上的意思,其实已经很明白了“懒汉模式”,顾名思义不同于饿汉模式,既然饿汉模式是不管三七二十一先吃了再说,那么懒汉模式当然就没那么勤快了,应该是被我们调用后的时候才去实例化对象。
它们的写法很类似,只不过是在用private static声明对象的时候不直接new对象,而是在gette方法里再去实例化对象
然后判断下这个对象是否为null,如果为null则实例化一个对象,如果不会空则直接返回对象。
下面看下具体代码
SimpletonDemo2.java(单例类)
package com.lcw.simpleton;
public class SimpletonDemo2 {
//将构造方法私有化,阻止外界直接创建对象
private SimpletonDemo2() {
}
//提供static以便外界访问
private static SimpletonDemo2 instance;
//提供getter方法以便外界访问私有化对象,static SimpleDemo1返回类型
public static SimpletonDemo2 getInstance() {
if(instance==null){
return instance=new SimpletonDemo2();
}else{
return instance;
}
}
}
SimpletonTest.java(测试类)
package com.lcw.simpleton;
public class SimpletonTest {
public static void main(String[] args) {
SimpletonDemo1 s1=SimpletonDemo1.getInstance();
SimpletonDemo1 s2=SimpletonDemo1.getInstance();
if(s1==s2){//检测对象的内存地址是否一致
System.out.println("s1和s2是同个对象");
}else{
System.out.println("s1和s2不是同个对象");
}
SimpletonDemo2 s3=SimpletonDemo2.getInstance();
SimpletonDemo2 s4=SimpletonDemo2.getInstance();
if(s3==s4){//检测对象的内存地址是否一致
System.out.println("s3和s4是同个对象");
}else{
System.out.println("s3和s4不是同个对象");
}
}
}
效果如下:

总结下两种模式的区别:
1、饿汉式,在加载类的时候比较慢,由于它还要去实例化一个对象并造成内存资源的浪费,但在运行调用中的速度会比较快。
2、懒汉式,在加载类的时候比较快,由于在加载类的时候不需要去实例化对象,但在运行调用时的速度比较慢,由于还要去做判断。
还有一点很重要的是,饿汉模式是属于线程安全,而懒汉模式属于线程不安全,在高并发时会出现问题。
那有没有更好的方式呢?答案肯定是有的,我们可以结合了饿汉式和懒汉式各自的优点,不在加载类的时候实例化不必要的对象,又同时具备了线程安全
说直白的点就是利用内部类去静态实例化这个对象,由于内部类需要在外部类被调用的时候才会去加载,也就是说不会在没必要的时候去加载对象从而导致系统资源的浪费,同时我们在内部类中对这个对象实行静态实例化也就避免了线程安全这个问题。
package com.lcw.simpleton;
public class SimpletonDemo {
// 将构造方法私有化,阻止外界直接创建对象
private SimpletonDemo() {
}
// 定义一个内部类用来实例化对象
private static class Inner_SimpletonDemo {
private static SimpletonDemo instance = new SimpletonDemo();
}
// 提供getter方法以便外界访问私有化对象,static SimpleDemo1返回类型
public static SimpletonDemo getInstance() {
return Inner_SimpletonDemo.instance;
}
}
再来看下最后一种实现方式,登记式
由于懒汉式和饿汉式都把构造方法私有化了,所以它不能被继承,登记式可以解决这个问题
登记式单例模式 类似于Spring里面的用法,将类名注册并放到Map集合里,下次要用的时候直接取
登记式实际对一组单例模式进行的维护,主要是在数量上的扩展,通过map我们把单例存进去,这样在调用时,先判断该单例是否已经创建,是的话直接返回,不是的话创建一个登记到map中,再返回。对于数量又分为固定数量和不固定数量的。下面采用的是不固定数量的方式,在getInstance方法中加上参数(string name),然后通过子类继承,重写这个方法将name传进去。
SimpletonDemo3.java(单例类)
package com.lcw.simpleton; import java.util.HashMap;
import java.util.Map; public class SimpletonDemo3 {
// 私有化构造器,保护钩子
private SimpletonDemo3() {
} private static Map<String, SimpletonDemo3> map = new HashMap<String, SimpletonDemo3>();
//静态代码块
static {
SimpletonDemo3 instance = new SimpletonDemo3();
map.put(instance.getClass().getName(), instance);
} // 参数name为类名
public static SimpletonDemo3 getInstance(String name) {
if (name == null) {
name = "com.lcw.simpleton.SimpletonDemo3";
}
if (!map.containsKey(name)) {
try {
map.put(name, (SimpletonDemo3) Class.forName(name)
.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
} }
SimpletonTest.java(测试类)
package com.lcw.simpleton;
public class SimpletonTest {
public static void main(String[] args) {
SimpletonDemo1 s1 = SimpletonDemo1.getInstance();
SimpletonDemo1 s2 = SimpletonDemo1.getInstance();
if (s1 == s2) {// 检测对象的内存地址是否一致
System.out.println("s1和s2是同个对象");
} else {
System.out.println("s1和s2不是同个对象");
}
SimpletonDemo2 s3 = SimpletonDemo2.getInstance();
SimpletonDemo2 s4 = SimpletonDemo2.getInstance();
if (s3 == s4) {// 检测对象的内存地址是否一致
System.out.println("s3和s4是同个对象");
} else {
System.out.println("s3和s4不是同个对象");
}
SimpletonDemo3 s5 = SimpletonDemo3.getInstance("com.lcw.simpleton.SimpletonDemo3");
SimpletonDemo3 s6 = SimpletonDemo3.getInstance("com.lcw.simpleton.SimpletonDemo3");
if (s5 == s6) {// 检测对象的内存地址是否一致
System.out.println("s5和s6是同个对象");
} else {
System.out.println("s5和s6不是同个对象");
}
}
}
效果图:

作者:Balla_兔子
出处:http://www.cnblogs.com/lichenwei/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!
软件设计模式之单例模式(JAVA)的更多相关文章
- 软件设计模式之适配器模式(JAVA)
什么是适配器模式? 在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的.适配器能将因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存 ...
- 设计模式之单例模式(JAVA实现)
单例模式之自我介绍 我,单例模式(Singleton Pattern)是一个比较简单的模式,我的定义如下: Ensure a class has only one instance,and provi ...
- GOF23种设计模式之单例模式(java)
GOF(group of four):四人帮 分类 创建者模式 单例模式 核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 优点: 由于单例模式只生成一个实例,减少了系统性能开销, ...
- Java中的设计模式之单例模式
Java中的单例模式 设计模式是软件开发过程中经验的积累 一.单例模式 1.单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控 ...
- Java常见设计模式之单例模式
1.何为单例模式? 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的 ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- java 23 - 2 设计模式之单例模式
单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢? A:把构造方法私有 B:在成员位置自己创建一个对象 C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...
- [转]JAVA设计模式之单例模式
原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...
- 设计模式 -- 单例模式(Java&&PHP)
所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在.就像是Java Web中的application,也就是提供了一个全局变量,用处相当广泛,比如保存全局数据,实现全局性的操作等. 能够 ...
随机推荐
- iOS概念之KVO(Key-Value Observing)
在一个复杂的,有状态的系统中,当一个对象的状态发生改变,如何通知系统,并对状态改变做出相应的行为是必需考虑的一个问题,在iOS中为这类问题提供了4种解决方法: 1. NSNotifiactaion和N ...
- kafka 怎么保证的exactly once
Kafka auto.offset.reset值详解 发表于2017/7/6 11:25:22 1010人阅读 分类: Kafka 昨天在写一个java消费kafka数据的实例,明明设置auto.o ...
- win7+php5.3.10下安装memcache (转)
因为升级到了5.3.10,所以之前的dll不能使用了,弄了好久,终于还是在老外的博客上找到了解决方法: (环境是win7+php5.3.10+win32) 1.解压附件memcached到某个目录,本 ...
- Nginx+php (十六)
[教程主题]:Nginx+php [课程录制]: 创E [主要内容] [1] 编译PHP 初始环境: 为了省事把所需要的库文件全都安装上,可以使用rpm包安装,也可以用yum命令安装, yum -y ...
- 实战c++中的string系列--string与char*、const char *的转换(data() or c_str())
在project中,我们也有非常多时候用到string与char*之间的转换,这里有个一我们之前提到的函数 c_str(),看看这个原型: const char *c_str(); c_str()函数 ...
- css限制显示字数,文字长度超出部分用省略号表示【转】
为了保证页面的整洁美观,在很多的时候,我们常需要隐藏超出长度的文字.这在列表条目,题目,名称等地方常用到. (1).文字超出一行,省略超出部分,显示'...' 如果这种情况比较多,可以取一个切合作用的 ...
- 百度地图的demo提示key验证错误!错误码:230;
在已经有BaiduMap的APIKey后使用AndroidStudio导入Baidu地图的as版的demo,提示key验证错误!错误码:230; 首先,因为百度地图demo中用自己的keystore文 ...
- 关于Unity中网格导航与寻路
寻路思路 1.烘焙出地形数据,导航数据,区分哪些是路径,哪些是障碍物 2.给要寻路的角色添加寻路的组件,加好了以后就会有速度和目的地之类的参数设置 3.只要设置好目的地,角色就会根据烘焙好的地图自己走 ...
- ACTIVE NEURAL LOCALIZATION
用贝叶斯滤波器定义状态,用rl帮助定位. 这个方法需要对地图和角度进行离散化,当地图很大,角度较精细时,输出会很大,所以不太可能用到大地图,高精度角度的任务上.
- Numpy 利用数组进行数据处理
Numpy数组使你可以将许多种数据处理任务表述为简洁的数组表达式(否则需要编写循环). 用数组表达式代替循环的做法,通常被称为矢量化.一般来说,矢量化数组运算要比等价的纯跑一趟湖南快 上一两个数量级( ...