static的应用:单例设计模式(Singleton)浅谈

设计模式:

通俗的理解就是套路。 和数据结构类似,设计模式是独立于语言的,只是Java在设计模式用得比较频繁。设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,针对不同的棋局,我们用不同的棋谱。

单例设计模式:

单例(singleton): 指的是单独的一个实例,实例就是对象的意思
也就是说我们只想造一个类的对象

单例设计模式就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
分析: 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了(new会调用构造器,调一次就产生一个对象),但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象 的变量也必须定义成静态的。

单例设计模式的两种写法:饿汉式和懒汉式

例子:比如我们希望创建的银行类是一个单例的,也就是说银行类只造一个对象
单例模式的饿汉式实现

package test01;
//单例设计模式的饿汉式实现有四个步骤
public class test {
	
	public static void main(String[] args) {
		Bank bank1=Bank.getInstance();
		Bank bank2=Bank.getInstance();//bank1和bank2是同一个对象,是我们在Bank类中唯一new的对象
		
		System.out.println(bank1==bank2);//true,表明地址值相同,也说明为同一个对象
	}
}
//银行类是单例的(单例的类可以有属性,构造器也可以带有形参)
class Bank{
	//1.私有化类的构造器。可以避免构造器在Bank类的外面被调用。
	//单例 要求有一个对象,外面又造不了对象,只能在类里面去造
	private Bank() {//如果没有private,哪怕是default权限都可以通过new制造多个对象,Bank这个类就不满足单例了
		
	}
	//2.内部创建类的对象。为了封装性,习惯上也进行私有化,通过方法去得到对象
	//4.把此对象也声明为静态的
	private static Bank instance=new Bank();//这个对象其实也可以理解为类的一个属性,只不过这个属性恰好是它的对象 
	
	//3.提供公共的方法返回类的对象。其实就相当于普通属性的get方法,一定要声明成static
	public static Bank getInstance() {//这样就可以通过类名去调用否则别的类由于创建不了这个类的对象无法调用这个方法
		return instance;//注意创建的对象也要是static,否则不能return
	}//因为静态方法中不能直接调用非静态的属性
}

单例模式的懒汉式实现:

package test01;
//单例模式的懒汉式实现有4个步骤
public class test {

	public static void main(String[] args) {
		Order order1=Order.getInstance();
		Order order2=Order.getInstance();

		System.out.println(order1==order2);//true,说明是同一个对象,说明只new过一次
	}

}

class Order{
	//1.私有化类的构造器。还是不能在类的外部创建当前类的对象
	private Order() {
		
	}
	//因为不能在外部创建当前类的对象,还是要在内部去创建对象,只是方式和饿汉式不同
	
	//2.声明当前类的对象变量,用private修饰
	//4.此对象变量也必须声明为static的
	//并没有一上来就去new,如果一上来就去new叫做饿汉式,懒汉式是先写null,先不去创建实例,而只是声明
	private static Order instance=null;
	
	//3.声明用public static修饰的返回当前类对象的方法,并在该方法中创建对象
	public static Order getInstance() {//注意:类方法只会随着类的加载而加载,并不会执行
		//instance=new Order();不能这么写,因为会使得每调用一次该方法就new一个对象,所以能够创建多个当前类的对象,就不是单例了
		if(instance==null) {
			//说明还没有创建过对象
			instance=new Order();
		}
		//如果已经创建了对象,直接把已经创建的对象return即可
		return instance;
	}
}

区分饿汉式和懒汉式:

饿汉式是一上来就把对象准备好,懒汉式是先不造对象,要用的时候再造对象
饿汉式:
坏处(相较于懒汉式来说): 虽然在一开始就把对象造好了,但是导致对象的加载时间过长。有可能我们暂时不去用,所以会在内存中加载很长的时间,相当于占用内存了。
好处: 饿汉式天然就是线程安全的

懒汉式:
坏处: 按照上面的写法是不安全的 :比如现在有两个线程都想去获取当前类的对象,第一个线程进来以后因为是首次调用(instance是null)进去if之后线程没有马上new 一个对象,而是发生了阻塞。此时另一个线程也进入了if,所以new了两次对象,所以上面的写法线程不安全,要想改成线程安全涉及到多线程的内容。如果用的时候涉及到多线程的问题要进行修改
好处: 延迟对象的创建。一开始先不去加载,当需要的时候才去创建

反映的static关键字的问题: 内存中只加载一份,对象用的时候早就有了,所以可以直接拿过来用,比较快,弊端就是生命周期过长,在内存中长时间存在,当类被处理掉时静态结构才会被处理掉。

注意: 在笔试中写饿汉式or懒汉式都行,如果写饿汉式按现在的版本写就可以了,因为饿汉式本身就是线程安全的。但如果写懒汉式不要写现在的版本会有线程安全问题,需要利用多线程的知识修改成线程安全的。

单例模式的优点:

由于单例模式只生成一个实例,减少了系统性能开销(不是从static的角度,是从单例的角度说的,当没有必要造多个对象的时候只去造一个),当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

java.lang.Runtime就是典型的单例模式

单例模式的应用场景:

1)网站的计数器,用来计算当前网站的浏览信息,一般也是单例模式实现,否则难以同步。
2) 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
3) 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
4)项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
5)Application 也是单例的典型应用
6)Windows的Task Manager (任务管理器)就是很典型的单例模式
7)Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

上一篇:数据库模拟银行业务(二)


下一篇:确定生成的日期是否属于假期(PHP)?