A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© @白纸嘿字@ 中级黑马   /  2015-10-13 00:29  /  6731 人查看  /  22 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

2黑马币
本帖最后由 @白纸嘿字@ 于 2015-10-13 00:31 编辑

  1. class Single{
  2.        //类已加载,对象就已经存在了
  3.        private static Single s = new Single();

  4.        private Single(){}

  5.        public static Single getInstance(){
  6.              return s ;
  7.       }
  8. }

  9. class SingleDemo{
  10.        public static void main(String[] args){
  11.             Single s1 = Single.getInstance();
  12.             Single s2 = Single. getInstance();
  13.             System.out.println(s1 == s2);
  14.       }
  15. }
复制代码


对单例设计模式,一直有好些个疑惑没有解开......
类都没有写完,都没有出花括号!怎么能在还没写完自己的时候,就用自己呢?
类加载中,怎么还能new对象,建立对象不是类加载完后的事吗?如果是这样的话,我能不能在这个静态方法里调用this,它这里有对象,是不是也就有this
像这个,还有递归,等等...它们一次又一次挑战自己理解的底线,每次看到这些,大脑中的本能反应就是“怎么还可以这样!”

22 个回复

倒序浏览
单例设计模式分两种:
第一种:饿汉式单例设计模式
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;
      }
}
回复 使用道具 举报
单例思想:
       1,不让其他程序创建该类对象。
       2,在本类中创建一个本类对象。
       3,对外提供方法,让其他程序获取这个对象。
步骤:
      1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该
            类对象;
     2,就在类中创建一个本类的对象;
     3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
代码体现:
   1,私有化构造函数;
   2,创建私有并静态的本类对象;
   3,定义公有并静态的方法,返回该对象。
---------------------------------------------
  1. //饿汉式
  2. class Single{
  3. private Single(){} //私有化构造函数。
  4.   private static Single s = new Single(); //创建私有并静态的本类对象。
  5. public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
  6. return s;
  7. }
  8. }
  9. ---------------------------------------------
  10. //懒汉式:延迟加载方式。
  11. class Single2{
  12. private Single2(){}
  13.   private static Single2 s = null;
  14. public static Single2 getInstance(){
  15. if(s==null)
  16. s = new Single2();
  17. return s;
  18. }
  19. }
复制代码


还有静态里面不能用this
单例模式的作用就是把对象私有化,并提供公共的方法让其他调用者获取这个对象,保证了对象的唯一性

点评

赞  发表于 2015-11-5 10:34
回复 使用道具 举报
懒汉式和饿汉式上面两位都给你说了,我给你说一个最简单的单例。
class Single
{
      private Single(){}
      public· static final Single INSTANCE = new Single();
}
还有,类一加载就可以new对象的。Java程序运行的时候,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,类的各种信息都在方法区中保存,而new是初始化对象,将对象放入堆内存中.
还有就是静态不能用this.
回复 使用道具 举报
放到内存中就好理解了,当Single类被加载到内存中的方法区的时候, private static Single s = new Single();是一个静态成员,它会先被加载到静态区, 在栈中会先有Single s的引用,然后根据该引用
在堆中创建一个对象new Single();
也就是说在方法区的该类的静态区,就已经在堆中加载完成了该对象
回复 使用道具 举报
本帖最后由 @白纸嘿字@ 于 2015-10-14 17:13 编辑

类加载中,还能new对象!如果是这样的话,有对象,不就有this?
回复 使用道具 举报
使用new创建对象和类加载不是一起执行的。
回复 使用道具 举报
在加载类文件时遇到new是不会创建对象的。加载类文件和使用new创建对象不是一起的。而是先加载类。再根据调用创建对象。当创建时,虚拟机已经有了该类文件了。
回复 使用道具 举报
类都没有写完,都没有出花括号!怎么能在还没写完自己的时候,就用自己呢?
答:单例模式是在程序运行时,只允许存在一个对象。这里的应用环境是一个类被调用时,调用者只能使用一个对象。你说的类没写完,编译时无法通过的。
类加载中,怎么还能new对象,建立对象不是类加载完后的事吗?如果是这样的话,我能不能在这个静态方法里调用this,它这里有对象,是不是也就有this!
答:类是先编译后运行的,你说的加载应该是运行,类在运行时,是有顺序的。静态成员和方法和类同时加载,当方法被调用并且使用到该类的对象时,才在堆内存中创建对象;静态方法中只可以用this();或者supper();语句。不能用this调用的,因为这个时候还没有对象。
像这个,还有递归,等等...它们一次又一次挑战自己理解的底线,每次看到这些,大脑中的本能反应就是“怎么还可以这样!”
针对这类问题,肯定是自己什么地方没想到或者没理解而已,建议多交流,多问,多记,希望能帮到你。下面是我就单例模式写的文章,欢迎你的光临。
http://blog.csdn.net/xinxiangshicheng666/article/details/49183171
回复 使用道具 举报
本帖最后由 @白纸嘿字@ 于 2015-10-18 11:33 编辑
Love1027 发表于 2015-10-17 07:46
类都没有写完,都没有出花括号!怎么能在还没写完自己的时候,就用自己呢?
答:单例模式是在程序运行时, ...

·“这里的应用环境是一个类被调用时”
是指类成员(属性和方法)被调用吧?

·“你说的类没写完,编译时无法通过的”
我想表达的是,怎么能在自己里面创建自己对象呢?

·“不能用this调用的,因为这个时候还没有对象”
有对象啊!——private static Single s = new Single()
回复 使用道具 举报
// .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
回复 使用道具 举报
关于单例设计模式,有七种实现方法。这个百度一下,有介绍的。
回复 使用道具 举报
Single s = new Single(),,       在  new Single()之前,声明Single s时,这个类就已经加载进来了
回复 使用道具 举报
吃饭工作睡觉 发表于 2015-10-16 16:13
在加载类文件时遇到new是不会创建对象的。加载类文件和使用new创建对象不是一起的。而是先加载类。再根据调 ...

“再根据调用创建对象”。
你这里的“调用”是什么意思,是不是“new”的意思?
回复 使用道具 举报
我一直想不通,怎么能在自己里面创建自己对象呢?
回复 使用道具 举报
类的成员初始化顺序:
1 父类静态成员和初始化块
2 子类静态成员和初始化块
3 父类实例成员和初始化块
4 父类构造函数
5 子类实例成员和初始化块
6 子类构造函数

LZ可以参照的理解下。另外,Java的单例模式照顾到线程安全时,使用楼上几位的double check方法并不一定达到预期效果,考虑到Java的内存模型比较模糊的问题。
回复 使用道具 举报
static 是一个静态修饰符,它会先被加载到静态区。在栈中会先有Single s的引用,然后会随着类加载,根据该引用在堆中创建一个对象new Single();
回复 使用道具 举报
ccwinner 发表于 2015-10-20 23:20
类的成员初始化顺序:
1 父类静态成员和初始化块
2 子类静态成员和初始化块

你能不能就这个具体的例子说一说,说的过程中,能不能紧紧围绕我的疑惑——“怎么能在自己里面创建自己对象”展开!
回复 使用道具 举报
首先单例模式有很多种,最熟悉的就是懒汉(预先加载模式)饿汉(延迟加载模式) 非安全
其实还有多线程安全加载模式、双重检验模式 这两种都是线程安全的。

其次 单利模式中的构造器和方法都为私有 返回的也为静态类值 保证了只能为此类所用 故是单例的。而楼主所说的调用,对象只有在需要被唤醒的时候才进行实例化。静态方法是类方法可直接被,而this 调用的是当前对象,所以你说可不可以用呢?
回复 使用道具 举报
路过,,,,蹭点经验
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马