hello!铁子,我是Java菜鸟Kerwin,这篇文章视图讲清楚单例设计模式中的饿汉式和懒汉式,如果觉得讲的还算不错,或许可以期待下我日后的Java相关知识分享文章,我们一起进步,不耽误你时间啦,冲冲冲!(真诚欢迎诸位大佬指出文章错误及不当之处,感激不尽)
设计模式简单普及
大白话简单普及下设计模式先;
设计模式就是类似于我们下棋时的常用的经典棋谱,不同的棋局,我们用不同的棋谱,这样就可以省去我们大量的二次思考摸索的时间,而设计模式类似于编程世界的棋谱;
单例设计模式
保证在某个类中只能存在一个对象实例,并且该类只提供一个取得对象实例的方法;
种类:懒汉式、饿汉式、双重检查锁、枚举单例模式、静态内部类单例模式等
实现步骤:(GirlFriend类为例讲解)三步走战略即可实现
- 1.构造器私有化-
- 2.类的内部创建对象
- 3.向外暴露一个静态的公共方法 getInstance
- 代码实现....
typescript
public class Journey {
public static void main(String[] args) {
}
}
class GirlFriend {
private String name;
//2.在类的内部直接创建【静态】对象---为了能够在静态方法中使用,
//返回gf对象,所以要修饰为static(整家风)
private static GirlFriend gf = new GirlFriend("小n");
//如何保障我们只能创建一个GirlFriend对象?(保持专一,懂?)三步走战略就可以实现
//1.构造器私有化,避免在类的外部创建对象(断外念)
private GirlFriend(String name) {
this.name = name;
}
//3.为了在外边可以使用,提供一个公共的static方法,返回gf对象(开豁口)
public static GirlFriend getInstance() {
return gf;
}
}
饿汉式VS懒汉式
总结就是一句话:饿汉子猴急,懒汉子被动
饿汉式
为什么叫饿汉式呢?因为gf对象直接在类中就创建好了,所以只要类一加载,那么这个对象就创建好了,即使没有使用gf对象,它也会被创建,所以叫饿汉式,显得很着急,还没有长大,脑海中就已经幻想拥有了女朋友(怪不得叫饿汉,我都没有这么想过);
typescript
public class Journey {
public static void main(String[] args) {
//通过方法可以获取对象,
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance);//GirlFriend{name='小n'}
//即使再获取一个对象,其还是会映射到"小n",这就是单例设计模式的精髓hhhh
GirlFriend instance2 = GirlFriend.getInstance();
System.out.println(instance2);//GirlFriend{name='小n'}
System.out.println(instance2 == instance);//true
}
}
class GirlFriend {
private String name;
private static GirlFriend gf = new GirlFriend("小n");
private GirlFriend(String name) {
this.name = name;
}
//这里如果没有static,你又得自己去new,又回到了之前的循环之中
public static GirlFriend getInstance() {
return gf;
}
@Override
//重写个toString方法,把初始化的gf对象的名字打出来
public String toString() {
return "GirlFriend{" + "name='" + name + ''' + '}';
}
}
再补充点细节
arduino
main方法中敲下这行语句: System.out.println(GirlFriend.age);
//这行语句实际上没有使用到gf对象,但是在使用静态属性age的时候,会导致GirlFriend类被加
//载,一旦类被加载了,则(***)这句静态属性初始化的代码语句是会被执行的,一旦(***)被执
//行则有参构造器private GirlFriend(String name) 会被调用,所以会
//会输出"GirlFriend构造器被调用!!!",而且是先输出
class GirlFriend {
private String name;
public static int age=100;
//此中的对象是核心,饿汉式可能造成创建了对象,但是没有使用。
private static GirlFriend gf = new GirlFriend("小n");//(***)
private GirlFriend(String name) {
System.out.println("GirlFriend构造器被调用!!!");
this.name = name;
}
public static GirlFriend getInstance() {//这里如果没有static,你又得自己去new,又回到了之前的循环之中
return gf;
}
@Override
//重写个toString方法,把初始化的gf对象的名字打出来
public String toString() {
return "GirlFriend{" + "name='" + name + ''' + '}';
}
}
//输出结果如下:
GirlFriend构造器被调用!!!
100
饿汉式可能没有去使用一个实例,但是他也会帮你创建了,但是懒汉式单例设计模式就不存在这个问题,你使用的时候才帮你创建(这家伙绝不会主动!!)
懒汉式
csharp
public class Journey {
public static void main(String[] args) {
//new Cat("大黄");//被private修饰,哪能随便让你创建对象
//使用Cat类的静态属性,此时类已经加载了,但是不同于饿汉式,
//其并没有创建cat对象,所以不会调用Cat类的构造方法
System.out.println(Cat.v1);//没有创建Cat对象,默认是null
}
}
//希望在程序运行过程中,只能创建一个Cat对象
class Cat{
private String name;
public static int v1 =999;
//步骤
// 2.定义一个静态static属性对象
private static Cat cat ;
// 1.仍然是构造器先私有化
private Cat(String name) {
System.out.println("Cat类的构造器被调用");
this.name = name;
}
// 3.提供一个公共的static方法,可以返回一个Cat对象
public static Cat getInstance(){
if(cat ==null){
cat = new Cat("魔拉");
}
return cat;
}
}
//此时输出的结果如下:
999
同样补充下懒汉式的细节
csharp
public class Journey {
public static void main(String[] args) {
//创建了一个实例,进入到getInstance()方法,发现cat为null,
//然后new一个Cat对象,给你return,此时有了对象之后,
//就会进入有参构造方法
Cat instance = Cat.getInstance();
System.out.println(instance);//尝试打印出此时创建出的猫的信息(if exist)
Cat instance2 = Cat.getInstance();//已经创建了一个实例之后,再尝试创建就会无功而返哟
System.out.println(instance2);//此时cat不等于null,就不会新创建啦,依旧打印之前的cat对象的信息
System.out.println(instance2==instance);//返回true
}
}
//希望在程序运行过程中,只能创建一个Cat对象
class Cat{
private String name;
public static int v1 =999;
//步骤
// 2.定义一个静态static属性对象
private static Cat cat ;
// 1.仍然是构造器先私有化
private Cat(String name) {
System.out.println("Cat类的构造器被调用");
this.name = name;
}
// 3.提供一个公共的static方法,可以返回一个Cat对象
public static Cat getInstance(){
if(cat ==null){
cat = new Cat("魔拉");
}
return cat;
}
}
//此时输出结果如下
Cat类的构造器被调用
Cat{name='魔拉'}
Cat{name='魔拉'}
true
懒汉式,只有当用户使用getInstance时,才返回cat对象,后面再次调用时,会返回上次创建的cat对象,从而保证了单例
小结
- 饿汉式和懒汉式,二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载时就创建了对象实例,而懒汉式是在使用时,才创建对象实例;
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式存在浪费资源的可能,因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
- 在JavaSE标准类中,java.lang.Runtime就是经典的单例模式,而且它是饿汉式的单例模式,可以自己查看源码了解(算了,我粘出来给你瞅一眼,粘错了别怪我)
csharp
public class Runtime {//Runtim的对应部分源码
//类加载时就创建对象--->饿汉式
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}
拜拜啦,希望我的文章对你学习Java或多或少有点帮助,欢迎诸位大佬在评论区留言指出文章的错误或文章讲解存在的问题(我太想进步了啊!!!)