单例模式简介
单例模式是软件设计模式中最简单的一种设计模式。从名称中可以看出,单例的目的就是使系统中只能包含有一个该类的唯一一个实例。
单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
本文将以Java语言来描述单例类的几种实现方式,以及分析给出的几种实现方式的优缺点和并用程序验证性能数据。
Java实例化的方式
我们知道在Java语言中创建实例的方法大体上有4种:
1、使用new关键字
import java.io.Serializable; import java.util.Random; /** * @author thinkpad * */ public class Singleton implements Serializable{ private static final long serialVersionUID = -3868390997950184335L; private static Random random = new Random(); private int id; private String name; private int [] data = { random.nextInt(), random.nextInt(), random.nextInt() }; //default constructor public Singleton(){ } //public constructor public Singleton(int id){ this.id = id * 2; } //private constructor private Singleton(int id,String name){ this(id); this.name = name + "." + name; } @Override public String toString(){ StringBuffer buf = new StringBuffer(); buf.append(super.toString()).append("\n") .append("id :").append(id).append("\n") .append("name :").append(this.name).append("\n") .append("data array :").append(data.toString()); return buf.toString(); } }
最常见的使用new 关键字,创建一个对象
public class TestSingleton { public static void main(String[] args) { Singleton single = new Singleton(1); } }
2、使用反射
使用反射能够突破JAVA中可见权限,本示例中调用了Singleton私有的构造方法。
import java.lang.reflect.Constructor; import java.lang.reflect.Type; /** * @author thinkpad * */ public class TestSingletonUseReflect { public static void main(String[] args) { try { Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors(); System.out.println(constructors.length); for(Constructor<?> con : constructors ) { Type[] types = con.getParameterTypes(); if (types.length == 2){ con.setAccessible(true); Singleton singleton = null; singleton = (Singleton) con.newInstance(1,"single1"); System.out.println(singleton); Singleton singleton2 = null; singleton2 = (Singleton) con.newInstance(2,"single2"); System.out.println(singleton2); } } }catch(Exception e){ e.printStackTrace(); } } }
3、使用反序列化
我们知道Java对象序列化(Object Serialization)将那些实现了Serializable接口的对象转换成一个字节序列,并可以通过反序列化将这个字节序列完全恢复成为原来的对象,因此反序列化提供了一个创建对象的方式。由于使用反序列化创建对象和使用new关键字创建对象有一些不同,反序列化过程中构造方法是没有被调用的(也不一定,若序列化对象父类没有实现Serializable接口,例如Object类,序列化过程中会递归调用父类的无参构造函数),而且其中的域的初始化代码也没有被执行。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @author thinkpad * */ public class TestSerializable { /** * @param args */ public static void main(String[] args) { Singleton single1 = new Singleton(100); Singleton single2 = new Singleton(200); try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buf); System.out.println("**********begin serializable**********"); System.out.println(single1); System.out.println(single2); out.writeObject(single1); out.writeObject(single2); out.close(); System.out.println("**********begin unserializable**********"); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray())); Singleton s1 = (Singleton)in.readObject(); Singleton s2 = (Singleton)in.readObject(); System.out.println(s1.toString()); System.out.println(s2.toString()); in.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
4、依赖注入(Spring DI)
依赖注入从JVM的角度来看的话,应该不算是一种创建对象的方式。关于依赖注入的概念,请参考Spring官方网站。
Java单例的几种实现方式
根据单例模式的定义及描述,要实现单例模式,有几个问题是需要考虑的。单例如何创建以及由谁创建,如何保证实例的唯一性,如何提供全局的访问点。由于Java语言中的实例化有多种,所以Java单例必须能够保证在各种条件下维持instance的唯一性,能够做到线程安全、延迟加载并且能够很好的抵抗反射攻击、反序列化攻击等。本文的以下内容将分析和验证常见的几种单例的设计方法,并用代码来验证效果(网上理论讲的很多,但是大部分都缺少实际的代码验证)。
实现单例,必须是私有的构造器,并导出公有的静态实例,根据静态实例的初始化方式,可以分为饿汉型和懒汉型,根据实例的暴露方式可以分为直接暴露和工厂方法间接暴露。饿汉型在类加载的时候就完成实例化,懒汉型就是在实际使用的时候才进行实例化。因此饿汉型的单例是能够保证线程安全的(JVM来保证ClassLoader只加载一次,不考虑多个ClassLoader的情况),懒汉型的线程安全却需要额外的同步来控制;饿汉型不能实现懒汉式的延迟加载。
1、直接暴露-饿汉型(1)
这种写法非常简单、粗暴,而且也能较好的满足需要,呵呵,有时候简单粗暴也是最能快速解决问题的。这种方式线程安全,但是缺乏灵活性,不容易扩展。
import java.io.Serializable; public class DirectHungrySingleton implements Serializable{ private static final long serialVersionUID = 6069877357741265707L; //实例对象 public static final DirectHungrySingleton singleton = new DirectHungrySingleton(); //私有的构造方法 private DirectHungrySingleton(){ } }2、工厂方法-饿汉型
相关推荐
单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类只有一个实例,并提供全局访问点。在Java中,实现单例模式有多种方法,每种方法都有其特点和适用场景。以下是对这六种常见单例模式实现方式的...
在 Java 中,单例模式的写法有好几种,主要有懒汉式单例、饿汉式单例、登记式单例等。 懒汉式单例是一种常见的单例模式实现方式,它在第一次调用的时候实例化自己。下面是懒汉式单例的四种写法: 1、基本懒汉式...
在Java语言中,实现单例模式主要有以下几种方式: 1. 饿汉式(Eager Initialization) 饿汉式单例模式在类加载的时候就已经进行了实例化,因此它不需要考虑多线程同步的问题。这种方式在类加载时就完成了初始化,...
【06期】单例模式有几种写法? 【07期】Redis中是如何实现分布式锁的? 【08期】说说Object类下面有几种方法呢? 【09期】说说hashCode() 和 equals() 之间的关系? 【10期】Redis 面试常见问答 【11期】分布式...
10. **设计模式**:常见的23种设计模式,如单例模式、工厂模式、观察者模式等,是解决常见问题的成熟解决方案。 11. **注解(Annotation)**:用于提供元数据,增强代码的功能和可读性。 12. **Lambda表达式**:...
Java是一种高级编程语言,由Sun Microsystems(现已被Oracle公司收购)于1995年发布。它被设计成跨平台的,能够在各种操作系统上运行,包括Windows、Mac OS和Linux。Java的基础入门学习通常涉及以下几个核心概念: ...
6. **单例模式的几种写法:** 单例模式保证一个类只有一个实例,并提供一个全局访问点。常见的单例实现方式有饿汉式、懒汉式、枚举类型以及利用双重检查锁定机制等。 7. **web.xml加载顺序:** 在Web应用中,web....
1. 单例模式:了解单例模式的几种写法,包括懒汉式、饿汉式、双重检查锁定式等。 2. JDK 中的设计模式:了解 JDK 中的设计模式,包括 IO 中的装饰模式和设配器模式等。 3. 框架中的设计模式:了解常用的设计模式,...
以下是几种实现方式: 1. **懒汉式** ```java public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {} public static Singleton getSingleton() { ...
本文将详细介绍如何正确地使用SharedPreferences,并提供一种优化的实现方式。 SharedPreferences的特点主要有以下几点: 1. **单例模式**:通过`Context.getSharedPreferences()`获取的SharedPreferences对象是...
单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。常见的单例实现有饿汉式(静态常量)、懒汉式(线程安全的双重检查锁定)和枚举单例等。 5. **递归算法** 递归是函数或方法在定义时调用自身...
C#是微软公司于2000年推出的一种面向对象的编程语言,它基于C++和Java的设计理念,支持类型安全和垃圾回收,拥有丰富的类库和强大的开发工具Visual Studio。面试中,面试官通常会考察以下几个方面的基础概念: 1. *...
描述 "ListadeContatos" 是标题的另一种写法,进一步证实了这一点。标签 "Kotlin" 提示我们该项目是使用 Kotlin 语言编写的,这是一种由 JetBrains 开发的现代编程语言,特别适合 Android 应用开发。 Kotlin 知识点...