单例模式是什么?
对象在全局只能有一个实例
为什么要使用单例模式?
静态方法和非静态方法的区别?
静态的方法:
能够在它的类的任何对象创建之前被访问,而不必引用任何对象,
并且static修饰的属性和方法在整个类中只有一份,可共享,放在方法区中。
非静态的方法:
在创建实例对象时,因为属性的值对于每个对象都各不相同,
因此在new一个实例时,栈中有个引用地址指向了 ---> 堆中new出来的实例化对象,里面包含对象独有的属性和方法,
再次new实例化有不同属性值的该对象时,会重新创建一个栈中的引用地址指向 ---> 堆中new出来的实例化对象。
为什么要使用单例模式而非静态方法?
从面向对象的方式:
静态方法是基于对象,单例模式是面向对象,
如果一个方法不受限于它存在类的实例对象,那么这个方法应该是静态的,如果确实要使用非静态的方法,但是只想维持一份实例化对象,只有一个对象可以访问该方法,那么就需要使用单例模式,
而且,如果需要在系统运行的时候就加载一些在整个类的生命周期都存在的属性和方法,那这些类最好是独一份并且可以共享的,否则new实例化对象时再重新赋值毫无意义且浪费内存,所以需要用静态方法或单例模式来维持这些独一份并且可以共享的属性和方法,静态方法虽然能同样解决问题,但是最好的解决方案应该是面向对象的单例模式。
从功能上:
静态方法和单例模式都能保证独一份,
但是单例模式可以控制单例数量,进行有意义的派生,对实例的创建有更自由的控制。
怎样实现单例?
类的构造方法私有化,保证其他类不能实例化该对象
本类中实例化该对象,保证该类在全局中存在
创建一个公有的方法,返回的结果是实例化的该对象,供别人使用
1、饿汉式单例
在类创建的时候就直接初始化该类
//代码实现public class HungryMan {
private HungryMan(){}
/*
static:
HUNGRY_MAN需要在调用getInstance()之前就已经被初始化了,只有static的成员才能在没有创建对象时 进行初始化。
类的static成员在类第一次被使用时初始化后就不会再被初始化,保证了单例。
final:
保证必须给 HungryMan HUNGRY_MAN 赋值,也就是必须实例化该类
*/
private static final HungryMan HUNGRY_MAN = new HungryMan();
public static HungryMan getInstance(){
return HUNGRY_MAN;
}
}
在多线程中使用饿汉式单例,8个线程只有一个线程能使用该类的构造方法,说明饿汉式单例是线程安全的
public class HungryMan {private HungryMan(){
System.out.println("饿汉式单例" + Thread.currentThread().getName());
}
private static final HungryMan HUNGRY_MAN = new HungryMan();
public static HungryMan getInstance(){
return HUNGRY_MAN;
}
public static void main(String[] args){
for (int i = 0; i <9 ; i++) {
new Thread(()->{
HungryMan.getInstance();
}).start();
}
}
}
//输出结果:饿汉式单例 Thread-0
优点:
线程安全。
缺点:
该类进入JVM时,不论该类会不会被使用就直接被实例化,浪费了内存空间。
2、懒汉式单例