面试的时候被问到单例模式如何只创建一个实例对象?在一个类中怎么能调用构造函数呢?
没回答上来。
单例模式和工厂模式
程杰的《大话设计模式》上有,讲得很通俗易懂。
单例模式有3个要点:
(1)某个类只能有一个实例(那如何确保它只有一个实例?)
在创建对象的时候,先判断对象是否存在?
(2)它必须自行创建这个实例(那它又是如何来创建这个实例呢?)
通过另外一个函数调用构造函数。
(3)它必须自行向整个系统提供这个实例那如何自行提供呢?
返回一个我自己。
public class GirlFriend{
private static GirlFriend girlFriend;//在我的定义里面,有一个静态的我自己
private String name;
private GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
//有一个静态的获取方法,调用我自身的私有构造
public static GirlFriend getInstance(String name){
if(girlFriend == null){
girlFriend = new GirlFriend(name);//它必须自行建立这个实例
//它必须自行向整个系统提供这个实例
}
return girlFriend;
}
}
9、单例模式中有个懒汉模式和饿汉模式?
曾看过一篇比较有趣的文章:单例模式–我的机器人女友
java写的,其中volatile
和synchronized
不太理解。
public class GirlFriend{
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
public void smile(){
System.out.println("smile");
}
public static void main(String[] args{
GirlFriend girlFriend = new GirlFriend("小丽");
girlFriend.smile();
}
}
//单例模式
public class GirlFriend{
public static GirlFriend girlFriend;
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
public static GirlFriend getInstance(String name){
if(girlFriend == null){
girlFriend = new GirlFriend(name);
}
}
public void smile(){
System.out.println("smile");
}
public static void main(String[] args{
//GirlFriend girlFriend = new GirlFriend("小丽");
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
}
}
//通过多线程破坏单例模式
//单例模式
public class GirlFriend{
public static GirlFriend girlFriend;
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
public static GirlFriend getInstance(String name){
if(girlFriend == null){
girlFriend = new GirlFriend(name);
}
}
public void smile(){
System.out.println("smile");
}
public static void main(String[] args){
//GirlFriend girlFriend = new GirlFriend("小丽");
for(int i = 0; i < 5; i++){//5个线程同时运行,顺利创建多个不同的对象。
new thread( new Runable(){
@Override
public void run(){
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
}
}).start();
/***********************************************
线程1 线程2
T1: if(girlFriend == null){
T2: if(girlFriend == null){
T3: girlFriend = new GirlFriend(name);
T4: girlFriend = new GirlFriend(name);
T5: return girlFriend;
T6: return girlFriend;
线程1和线程2判断girlFriend的时候如果都为空,就会各自创建一个对象,最后就会返回两个不同的对象了。
***********************************************/
}
}
}
//懒汉式:添加同步锁
public class GirlFriend{
public static GirlFriend girlFriend;
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
//既然多线程会破坏单例模式,那么使用进程互斥就可以阻止多线程的不安全问题了。
//使用互斥锁synchronized
public synchronized static GirlFriend getInstance(String name){
if(girlFriend == null){
girlFriend = new GirlFriend(name);
}
return girlFriend;
}
/*
使用互斥锁会产生一些效率问题。
synchronized同步方法只有第一次创建对象的时候用得到,一旦创建了girlFriend对象后
就用不到这个同步功能了,以后每次调用getInstance方法都会同步代码,严重降低了效率。
*/
public void smile(){
System.out.println("smile");
}
public static void main(String[] args){
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
}
}
//饿汉式:在类加载的时候就创建对象。
public class GirlFriend{
public static GirlFriend girlFriend = new GirlFriend("小丽);
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
public static GirlFriend getInstance(String name){
return girlFriend;
}
/*
存在的问题:
(1)不支持延迟加载(在真正用到对象的时候,再创建实例);在类加载的时候,对象就创建好了。
如果对象在整个过程中一次都用不到,提前创建就浪费了。
(2)不能控制对象的数量,完全可以声明多个对象,比如
GirlFriend girlFriend1;
GirlFriend girlFriend2;
GirlFriend girlFriend3;
(3)可能没有足够的信息在静态初始化时,实例化每个对象,对象的构造方法参数可能要依赖程序后面的运算结果。
*/
public void smile(){
System.out.println("smile");
}
public static void main(String[] args){
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
}
}
//双重检测
public class GirlFriend{
//volatile关键字保证了每个线程看到的girlFriend对象都是最新的。
public volatile static GirlFriend girlFriend;
private String name;
public GirlFriend(String name){
this.name = name;
System.out.println("制作完成");
}
public static GirlFriend getInstance(String name){
if(girlFriend == null){//检查girlFriend对象的时候,如果为null就进入同步代码
synchronized (GirlFriend.class){
if(girlFriend == null){//每个线程重新判断 volatile girlFriend对象是否为空,
girlFriend = new GirlFriend(name);
}
}
}
return girlFriend;
}
public void smile(){
System.out.println("smile");
}
public static void main(String[] args){
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
}
}