什么是单例?
所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。
介绍一下static用法(预备知识)
1.类的静态成员属于类,不属于对象
2.类的静态成员,不需要对象或指向对象的指针进行引用
3.类的静态成员在引用时要遵循访问权限
使用:
1)在类内定义,类外初始化
2)静态数据成员必须初始化,且只能在类外初始化
3)在编译阶段,系统就会为类的静态成员分配单元,存储值
访问:
1)静态数据成员不能通过对象进行访问
2)访问方式 类名::静态数据成员名
#include<iostream>
using namespace std;
class My{
private :
int x;
static int sum;
public :
My(){
}
My(int x){
this->x = x;
}
int Getx(){
return x;
}
static void add(int n1,int n2,int n3){
sum = n1+n2+n3;
cout<<"sum is :____"<<sum <<endl;
}
};
int My::sum = 0; //这句必须有!!! ??
int main(void)
{
My my1(3);
My my2(7);
My *p = new My(2);
My::add(my1.Getx() , my2.Getx() , p->Getx());
return 0;
}
单例模式(懒汉模式C++)
/*
确保只有单个对象被创建。
这个类提供了一种访问其唯一的对象的方式,
可以直接访问,不需要实例化该类的对象。
多线程并发没有考虑,在后边的Java代码中进行补充
*/
#include<iostream>
using namespace std;
class Sington{
private :
static Sington*Instance; // 静态成员
Sington(){
cout<<"Singleton construct "<<endl; //只能调一次构造
}
public :
static Sington *Create(){ //静态方法 调 静态成员
if(!Instance){
Instance=new Sington(); //只执行一次
}
return Instance;
}
void fun(){
cout<<"调用~~~"<<endl;
}
};
Sington *Sington::Instance=NULL;
int main(void)
{
Sington *p;
p=Sington::Create();
cout<<p<<endl;
p->fun();
Sington *q;
q=Sington::Create();
cout<<q<<endl; //p、q值相同
}
懒汉模式与饿汉模式区别对比
1)一个类只能创建一个实例
2)构造函数和静态变量(加载类时即初始化)需为private
3)get方法应该为public static,可供全局访问
//懒汉模式
public class lazySingleton {
private static lazySingleton singleton=null; //懒,所以就不实例化了,加载类较快,但是第一次访问类可能会有点慢
private lazySingleton(){
//nothing
}
public static lazySingleton getSingleton(){
if(singleton==null){
synchronized (this){
if(singleton==null) //这里的二次判断很有必要啊,在多线程中同时到达第一个if的可能有多个,若此处没有二次二次判断,会导致new singleton()同步执行多次。
singleton=new lazySingleton();
}
}
return singleton;
}
}
//饿汉模式
public class hungrySingleton {
private static final singleton=new hungerySingleton();//此处最好不要丢掉final
private hungrySingleton(){
//noting
}
public static hungrySingleton getSingleton(){
return singleton();
}
}
下面的代码在多线程并发时,很容易出现安全隐患
public static LazySingle getInstance() {
if (sInstance == null) {
sInstance = new LazySingle();
}
return sInstance;
}
第一个线程进来判断 sInstance == null,还没有new 出实例的时候 。这个时候第二个线程也进来了,判断的sInstance 也是 null,然后也会 new 出实例的,这样就不是我们所要的单例模式了。那我们就需要加锁了,使用 synchronized 关键字。
饿汉模式更加安全简单~