什么是单例模式?
- 单例模式: 就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
- 单例模式有两种方式:
1、饿汉模式;
2、懒汉模式; - 两者之间的区别的什么?
饿汉式写法
package 单例模式;
public class 饿汉式 {
public static void main(String[] args) {
/**
* 传统的写法 可以一直new一个老婆,而老婆只能有一个,这不叫单例模式,怎么解决呢???
*/
Wife wife = new Wife("小红");
Wife wife2 = new Wife("小芳");
Wife wife3 = new Wife("小蓝");
}
}
// 一个人只能有一个老婆
class Wife{
private String name;
//
public Wife(String name) {
this.name = name;
}
}
改进
package 单例模式;
/**
* 步骤如下:
* 1、构造器私有化 --> 防止用户直接new一个对象
* 2、类的内部创建对象
* 3、向外暴露一个静态的公有方法。 getInstance()
*/
public class 饿汉式 {
public static void main(String[] args) {
//现在我们就只剩一个对象了,直接使用就好了
Wife wife = Wife.getInstance();
System.out.println(wife);
Wife wife2 = Wife.getInstance();
System.out.println(wife2);
System.out.println(wife == wife2); // 同一个对象 True
}
}
/**
* 小结:
* 饿汉式的单例模式通常是一个重量级对象
* 饿汉式的写法可能会造成资源的浪费,因为随着类的加载,(static)它会直接创建对象(着急),可能导致这个对象未被我们使用,但一直存在于内存当中
*/
// 一个人只能有一个老婆
class Wife{
private String name;
//2、类的内部创建对象(该对象必须是静态的)
//为了能够在静态方法中,返回wife对象,需要将其修饰为static
private static Wife wife = new Wife("小芳"); //静态相关的属性,在类加载的时候就调用了,且只会调用一次
private Wife() {
System.out.println("构造器被调用了...");
}
//1、构造器私有化 --> 防止用户直接new一个对象
private Wife(String name) {
System.out.println("构造器被调用了...");
this.name = name;
}
//3、向外暴露一个静态的公有方法,可以返回wife对象。 如:getInstance()
//如果去掉static 说明它不是一个静态方法,调用时还是需要new一个对象,这样就不算单例模式了
public static Wife getInstance(){
return wife;
}
@Override
public String toString() {
return "Wife{" +
"name='" + name + '\'' +
'}';
}
}
懒汉式写法
package 单例模式;
/**
* 步骤:
* 1、构造器私有化 --> 防止直接new
* 2、类的内部创建对象
* 3、向外暴露一个静态的公有方法
*/
public class 懒汉式 {
public static void main(String[] args) {
Cat cat = Cat.getInstance();
System.out.println(cat);
Cat cat2 = Cat.getInstance();
System.out.println(cat2);
System.out.println(cat == cat2); //对象地址相同 True
}
}
//希望在程序运行过程中,创建一只猫
class Cat{
private String name;
// 2、类的内部创建对象
private static Cat cat; //这里由于是懒汉式,因此不直接创建对象,这样就不会对资源产生浪费了
// 1、构造器私有化 --> 防止直接new
private Cat() {
System.out.println("构造器被调用...");
}
// 1、构造器私有化 --> 防止直接new
private Cat(String name) {
System.out.println("构造器被调用...");
this.name = name;
}
// 3、向外暴露一个静态的公有方法
public static Cat getInstance(){
//如果还没有创建Cat对象(调用了getInstance()才创建)
if (cat == null){
cat = new Cat("大花猫");
}
return cat;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
两者之间的区别
- 二者最主要的区别在于创建对象的时机不同 :
- 饿汉式:是在类加载的时候就创建了对象实例
- 懒汉式:是在使用的时候才创建的 - 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
- 饿汉式存在浪费资源的可能。
- 因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了 - 懒汉式是使用时才创建,就不存在这个问题了。