什么是单例模式?

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

单例模式的特点:

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)的更多相关文章

  1. 软件设计模式之适配器模式(JAVA)

    什么是适配器模式? 在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的.适配器能将因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存 ...

  2. 设计模式之单例模式(JAVA实现)

    单例模式之自我介绍 我,单例模式(Singleton Pattern)是一个比较简单的模式,我的定义如下: Ensure a class has only one instance,and provi ...

  3. GOF23种设计模式之单例模式(java)

    GOF(group of four):四人帮 分类 创建者模式 单例模式 核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 优点: 由于单例模式只生成一个实例,减少了系统性能开销, ...

  4. Java中的设计模式之单例模式

    Java中的单例模式 设计模式是软件开发过程中经验的积累 一.单例模式 1.单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控 ...

  5. Java常见设计模式之单例模式

         1.何为单例模式? 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的 ...

  6. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  7. java 23 - 2 设计模式之单例模式

    单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢?  A:把构造方法私有  B:在成员位置自己创建一个对象  C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...

  8. [转]JAVA设计模式之单例模式

    原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...

  9. 设计模式 -- 单例模式(Java&&PHP)

    所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在.就像是Java Web中的application,也就是提供了一个全局变量,用处相当广泛,比如保存全局数据,实现全局性的操作等. 能够 ...

随机推荐

  1. Win7 IIS7 HTTP 错误 404.2 - Not Found解决方法 ISAPI CGI

    Win7 +IIS 刚配置的网站,输入网址后报以下错误: 应用程序“PFIZERQUERY”中的服务器错误 Internet Information Services 7.5 错误摘要 HTTP 错误 ...

  2. postgresql相关命令

    1,打开命令窗口: 2,查看数据库用户:\du 3,列出所有数据库名:\l或者SELECT datname FROM pg_database; 4,切换某个数据库下面的某个用户下面:\c 数据库名 用 ...

  3. mysql 通过使用联全索引优化Group by查询

    /*SELECT count(*) FROM (*/ EXPLAIN SELECT st.id,st.Stu_name,tmpgt.time,tmpgt.goutong FROM jingjie_st ...

  4. Winform鼠标滑轮控制自定义滚动条

    场景:类似QQ聊天的窗体中,需要添加自定义滚动条vScroll.主窗体中panel存放空间,右边有垂直的滚动条vScroll. 问题:已经实现vScroll和Panel.VerticalScroll滚 ...

  5. velocity单引号与双引号

    (1)最外层是用单引号包围时,双引号直接使用就可以了,两个连续的单引号表示一个单引号:#set($var2 = 'A"B''C') --> $var2 的值为 A"B'C(2 ...

  6. C语言 · 扶老奶奶过街

    算法提高 扶老奶奶过街   时间限制:1.0s   内存限制:256.0MB      一共有5个红领巾,编号分别为A.B.C.D.E,老奶奶被他们其中一个扶过了马路. 五个红领巾各自说话: A :我 ...

  7. virtualbox ubuntu 虚拟画面卡顿问题

    要在虚拟机全局配置里面添加选项:

  8. OpenWRT中的按键和灯的GPIO控制实现_转

    本文转自:OpenWRT中的按键和灯的GPIO控制实现 基于BarrierBreaker版本,基于AR9331 AP121 Demo单板 来进行描述 1.灯 A.在mach-ap121.c中,定义了灯 ...

  9. jmx学习

    原文地址:https://www.cnblogs.com/dongguacai/p/5900507.html 一.JMX的定义 JMX(Java Management Extensions)是一个为应 ...

  10. R语言中的factor

    对于初学者来说,R语言中的factor有些难以理解.如果直译factor为“因子”,使得其更加难以理解.我倾向于不要翻译,就称其为factor,然后从几个例子中理解: <span style=& ...