黑马程序员技术交流社区
标题: 单例设计模式 [打印本页]
作者: @白纸嘿字@ 时间: 2015-10-13 00:29
标题: 单例设计模式
本帖最后由 @白纸嘿字@ 于 2015-10-13 00:31 编辑
- class Single{
- //类已加载,对象就已经存在了
- private static Single s = new Single();
- private Single(){}
- public static Single getInstance(){
- return s ;
- }
- }
- class SingleDemo{
- public static void main(String[] args){
- Single s1 = Single.getInstance();
- Single s2 = Single. getInstance();
- System.out.println(s1 == s2);
- }
- }
复制代码
对单例设计模式,一直有好些个疑惑没有解开
......类都没有写完,都没有出花括号!怎么能在还没写完自己的时候,就用自己呢?
类加载中,怎么还能new对象,建立对象不是类加载完后的事吗?如果是这样的话,我能不能在这个静态方法里调用this,它这里有对象,是不是也就有this!
像这个,还有递归,等等...它们一次又一次挑战自己理解的底线,每次看到这些,大脑中的本能反应就是“怎么还可以这样!”
作者: zhp19821223 时间: 2015-10-13 01:32
单例设计模式分两种:
第一种:饿汉式单例设计模式
class Person{
private static Person P = new Person();
private Person(){
}
public static Person getInstance(){
return p;
}
}
第二种:懒汉式单例设计模式
1、不考虑安全和效率
class Person{
private static Person P;
private Person(){
}
public static Person getInstance(){
if(p==null){
p=new Person();
}
return p;
}
}
2、即考虑安全又考虑效率
class Person{
private static Person P;
private Person(){
}
public static Person getInstance(){
if(p==null){
synchronized(Person.class){
if(p==null){
p=new Person();
}
}
}
return p;
}
}
作者: 920792433 时间: 2015-10-13 19:54
单例思想:
1,不让其他程序创建该类对象。
2,在本类中创建一个本类对象。
3,对外提供方法,让其他程序获取这个对象。
步骤:
1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该
类对象;
2,就在类中创建一个本类的对象;
3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
代码体现:
1,私有化构造函数;
2,创建私有并静态的本类对象;
3,定义公有并静态的方法,返回该对象。
---------------------------------------------
- //饿汉式
- class Single{
- private Single(){} //私有化构造函数。
- private static Single s = new Single(); //创建私有并静态的本类对象。
- public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
- return s;
- }
- }
- ---------------------------------------------
- //懒汉式:延迟加载方式。
- class Single2{
- private Single2(){}
- private static Single2 s = null;
- public static Single2 getInstance(){
- if(s==null)
- s = new Single2();
- return s;
- }
- }
复制代码
还有静态里面不能用this
单例模式的作用就是把对象私有化,并提供公共的方法让其他调用者获取这个对象,保证了对象的唯一性
作者: VV烽火 时间: 2015-10-13 23:41
懒汉式和饿汉式上面两位都给你说了,我给你说一个最简单的单例。
class Single
{
private Single(){}
public· static final Single INSTANCE = new Single();
}
还有,类一加载就可以new对象的。Java程序运行的时候,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,类的各种信息都在方法区中保存,而new是初始化对象,将对象放入堆内存中.
还有就是静态不能用this.
作者: chengaq0 时间: 2015-10-14 10:47
放到内存中就好理解了,当Single类被加载到内存中的方法区的时候, private static Single s = new Single();是一个静态成员,它会先被加载到静态区, 在栈中会先有Single s的引用,然后根据该引用
在堆中创建一个对象new Single();
也就是说在方法区的该类的静态区,就已经在堆中加载完成了该对象
作者: @白纸嘿字@ 时间: 2015-10-14 17:07
本帖最后由 @白纸嘿字@ 于 2015-10-14 17:13 编辑
类加载中,还能new对象!如果是这样的话,有对象,不就有this?
作者: 吃饭工作睡觉 时间: 2015-10-16 16:01
使用new创建对象和类加载不是一起执行的。
作者: 吃饭工作睡觉 时间: 2015-10-16 16:13
在加载类文件时遇到new是不会创建对象的。加载类文件和使用new创建对象不是一起的。而是先加载类。再根据调用创建对象。当创建时,虚拟机已经有了该类文件了。
作者: Love1027 时间: 2015-10-17 07:46
类都没有写完,都没有出花括号!怎么能在还没写完自己的时候,就用自己呢?
答:单例模式是在程序运行时,只允许存在一个对象。这里的应用环境是一个类被调用时,调用者只能使用一个对象。你说的类没写完,编译时无法通过的。
类加载中,怎么还能new对象,建立对象不是类加载完后的事吗?如果是这样的话,我能不能在这个静态方法里调用this,它这里有对象,是不是也就有this!
答:类是先编译后运行的,你说的加载应该是运行,类在运行时,是有顺序的。静态成员和方法和类同时加载,当方法被调用并且使用到该类的对象时,才在堆内存中创建对象;静态方法中只可以用this();或者supper();语句。不能用this调用的,因为这个时候还没有对象。
像这个,还有递归,等等...它们一次又一次挑战自己理解的底线,每次看到这些,大脑中的本能反应就是“怎么还可以这样!”
针对这类问题,肯定是自己什么地方没想到或者没理解而已,建议多交流,多问,多记,希望能帮到你。下面是我就单例模式写的文章,欢迎你的光临。
http://blog.csdn.net/xinxiangshicheng666/article/details/49183171
作者: @白纸嘿字@ 时间: 2015-10-18 11:32
本帖最后由 @白纸嘿字@ 于 2015-10-18 11:33 编辑
·“这里的应用环境是一个类被调用时”
是指类成员(属性和方法)被调用吧?
·“你说的类没写完,编译时无法通过的”
我想表达的是,怎么能在自己里面创建自己对象呢?
·“不能用this调用的,因为这个时候还没有对象”
有对象啊!——private static Single s = new Single()
作者: 水瓶座的LoveD 时间: 2015-10-19 00:41
// .h文件
#define SingletonH(name) + (instancetype)shared##name;
// .m文件
#if __has_feature(objc_arc)
#define SingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
}
#else
#define SingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
} \
\
- (oneway void)release { } \
- (id)retain { return self; } \
- (NSUInteger)retainCount { return 1;} \
- (id)autorelease { return self;}
#endif
作者: daiqingming 时间: 2015-10-19 18:01
关于单例设计模式,有七种实现方法。这个百度一下,有介绍的。
作者: 1312564637 时间: 2015-10-20 15:57
Single s = new Single(),, 在 new Single()之前,声明Single s时,这个类就已经加载进来了
作者: @白纸嘿字@ 时间: 2015-10-20 17:02
“再根据调用创建对象”。
你这里的“调用”是什么意思,是不是“new”的意思?
作者: @白纸嘿字@ 时间: 2015-10-20 17:14
我一直想不通,怎么能在自己里面创建自己对象呢?
作者: ccwinner 时间: 2015-10-20 23:20
类的成员初始化顺序:
1 父类静态成员和初始化块
2 子类静态成员和初始化块
3 父类实例成员和初始化块
4 父类构造函数
5 子类实例成员和初始化块
6 子类构造函数
LZ可以参照的理解下。另外,Java的单例模式照顾到线程安全时,使用楼上几位的double check方法并不一定达到预期效果,考虑到Java的内存模型比较模糊的问题。
作者: doudou966 时间: 2015-10-21 02:08
static 是一个静态修饰符,它会先被加载到静态区。在栈中会先有Single s的引用,然后会随着类加载,根据该引用在堆中创建一个对象new Single();
作者: @白纸嘿字@ 时间: 2015-10-21 14:58
你能不能就这个具体的例子说一说,说的过程中,能不能紧紧围绕我的疑惑——“怎么能在自己里面创建自己对象”展开!
作者: cchjywall 时间: 2015-10-22 19:44
首先单例模式有很多种,最熟悉的就是懒汉(预先加载模式)饿汉(延迟加载模式) 非安全
其实还有多线程安全加载模式、双重检验模式 这两种都是线程安全的。
其次 单利模式中的构造器和方法都为私有 返回的也为静态类值 保证了只能为此类所用 故是单例的。而楼主所说的调用,对象只有在需要被唤醒的时候才进行实例化。静态方法是类方法可直接被,而this 调用的是当前对象,所以你说可不可以用呢?
作者: orgcheng 时间: 2015-10-22 20:30
路过,,,,蹭点经验
作者: 吃饭工作睡觉 时间: 2015-10-26 09:25
对,使用“new”调用的。
作者: 上帝的寵兒 时间: 2015-10-29 19:09
jvm编译java程序时,是把整个.java文件编译成.class文件。在运行的时候jvm才会按照程序结构从main入口处开始执行程序。你是把编译和运行弄混了。希望对你有帮助。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |