java单例模式(饿汉式、懒汉式、静态内部类式、枚举式)

单例模式特点是只能创建一个对象,单例模式有四种类型,分别是饿汉式、懒汉式、静态内部类式、枚举式,下面将分别介绍。在介绍之前,先讲解一些辅助知识点铺垫。
#####1、理解静态成员、实例成员、局部变量什么时候被加载初始化
(1)静态成员:这里静态成员指的是类的静态变量和静态方法;当类加载的时候,静态成员也会被加载到内存中,直到类消失它才会从内存中消失。
(2)实例成员:实例成员是类的非静态变量和方法,只有类的对象被创建了,实例成员才会被加载到内存中,随着对象被回收,实例成员也会被回收。
(3)局部成员:通常指的是局部变量,局部变量是在方法内部,通常方法被调用,局部变量才会被加载,方法用完了,局部变量就会被回收了,生命周期很短。
#####2、饿汉式
(1)饿汉式的特点:线程安全,调用效率高,不能够延时加载
(2)代码展示:

/**
 * 饿汉式
 * 
 * @author limingxing
 *
 */
class HungrySingleton {
	// 类初始时,立即加载这个这个对象。
	private static HungrySingleton instance = new HungrySingleton();

	// 外部不能通过构造方法创建对象了
	private HungrySingleton() {

	}

	// 只能通过getInstance方法获取此类对象
	public static HungrySingleton getInstance() {
		return instance;
	}
}
public class Test{
	public static void main(String[] args) {
		HungrySingleton hs = HungrySingleton.getInstance();
		HungrySingleton hs2 = HungrySingleton.getInstance();
		System.out.println(hs);
		System.out.println(hs2);
	}

结果:
java单例模式(饿汉式、懒汉式、静态内部类式、枚举式)_第1张图片
(3)代码解释:当这个类被用到时,就去会内存中寻找,要是内存中没有加载这个类,那么立即加载这个类,类初始化时,执行类的内部代码,静态成员就会被加载到内存中,这时instance对象就会被放到内存中,强调一点instance这时已经是一个HungrySingleton对象,方法getInstance也会被加载,因为是静态的。在主方法通过方法getInstance得到对象,getInstance方法返回的是instance,这时的instance在类初始后就是一个对象了,所有得到的就是一个对象。当第二次调用getInstance方法时,返回的是又是instance,因为内存中的instance还没有被回收,程序结束才会被回收,所有instance对象还是还是和上面一样,输出的地址值(哈希码)一样,保证了单例模式。之所以线程安全是因为线程还没启动时,类初始后instance对象就创建好了;高效率时,还是因为用的时候不要再加载,在用之前就加载到内存中了,直接用就好了;不能延迟加载也是因为类加载初始化instance对象就创建好了,还没来得及操作。
#####3、懒汉式
(1)懒汉特点是:线程安全,调用效率不高,可以延时加载,这里之所以说线程安全是因为用了synchronized关键字,要不然线程不安全,注意看清。
(2)代码

/**
 * 懒汉式
 * @author limingxing
 *
 */
class LazySingleton {
	//类初始化时,虽然有给instance分配内存,但是它还不是一个LazySingleton对象。
	private static LazySingleton instance;

	private LazySingleton() {

	}
	//有了synchronized关键字,线程就安全了。
	public static synchronized LazySingleton getInstance() {
		//如果是第一次通过方法得到对象,那么就会创建一个对象,后面就还是这个对象。
		if (instance == null) {
			instance = new LazySingleton();
		}
		return instance;
	}
}

(3)代码解释:不再像前面那么详细了,自己学着分析。线程安全是因为有synchronized关键字,多个线程同时访问这个资源时,只能同步访问;效率不高因为后面还要创建对象,刚开始没有创建对象,创建好对象后,每次拿到这个对象,还要判定是否为空,最重要的是实现同步,意味着其它线程需要等待;延时加载因为你想什么创建,调用getInstance方法,达到控制延时,不像饿汉式类初始化就创建对象了。
#####4、静态内部类式
(1)静态内部类式特点:线程安全,调用效率高,可以延时加载。
(2)代码:

/**
 * 静态内部类式
 * @author limingxing
 *
 */
class StaticInnerSingleton{
	//静态内部类,只有静态内部类的静态属性被调用时,才会加载,可实现延时加载功能。
	private static class Inner{
		private static final StaticInnerSingleton instance = new StaticInnerSingleton();
	}
	private StaticInnerSingleton() {
		
	}
	//方法没有同步,调用效率高
	public static StaticInnerSingleton getInstance() {
		return Inner.instance;
	}
}

(3)解释:线程安全是因为只要一个线程调用getInstance()方法,那么instance就是一个对象,而且用了static final修饰,保证了内存中只有这样一个实例存在,其它线程都是用instance对象。延迟加载因为静态内部类的静态内容只有被使用才会加载。高效是可以直接用,不需要等待,因为没有同步。
5、枚举式
(1)枚举式特点:线程安全,调用效率高,不能延时加载。
(2)代码:

public class Test4 {
	public static void main(String[] args) {
		EnumSingleton es = EnumSingleton.INSTANCE;
	    EnumSingleton es2 = EnumSingleton.INSTANCE;
	    System.out.println(es==es2);
	}
}

enum EnumSingleton{
	//类似public static final Enumsingleton instance = new EnumSingleton();
	INSTANCE;
	public void EnumSingleton() {
		
	}
}

(3)解释和前面差不多,不再赘述。

你可能感兴趣的:(一,java基础)