黑马程序员技术交流社区

标题: 单例模式的疑问 [打印本页]

作者: 莫道荣    时间: 2013-3-5 22:21
标题: 单例模式的疑问
本帖最后由 莫道荣 于 2013-3-11 19:54 编辑

大家知道在java语言中,可以利用static 关键字来构建单例模式,主要是因为static 这个关键字在所在的类在被java虚拟机装载的时候,变量是最先被装载(如果有多个,那么按照从上往下的顺序执行的),并且是全局共享的。
    因此:按照这个理解:我写了一个单例模式。代码如下:
    public class Test{
    private static Test test=null;
    public static Test getInstence(){
                 if(test==null)
                {
                     test=mew Test();
                }
                  return test;
      }
   }
       在这个方法里,我申明了一个private static类型的成员变量,然后申明了一个static类型的方法,判断test如果是null,则实例化,然后返回Test类的一个实例。应为static类型的变量是全局共享的,所以,一旦test被实例化,那么则被存放到java虚拟机的堆中,全局共享,以后不会在实例化。直到类的生命周期结束然后才会被销毁。在别的类要引用的时候,只需要Test.getInstence()就可以获得一个实例。这就是我理解的单利模式。

    但我在网上看了另一种写法,说要有一个私有的构造函数,代码是这样的。
   
  public class Test{
      private Test(){}
      private static Test test=new Test();
      public static Test getInstence(){
  
         return test;
      
       }
  }
我是这样理解这个类的:
1    private static Test test=new Test();在jvm 装载这个类的时候会初始化这个声明,Test类的实例test已经被实例化。并且全局共享。
2     public static Test getInstence(){
  
         return test;
      
       }
  static的方法getInstence用来返回Test 类的实例。这个实例就是上面已经实例化的那个(唯一的一个)
问题一:问题是私有的构造函数,我不明白为什么一定要有个私有的构造函数?大家帮  忙看看!
问题二:在开发单例模式中有那些是需要注意的地方?比如构造方法之类的要注意什 么?
问题三:单利模式有几种形式?能不能给个例子?听说有懒汉式什么的?
问题四:什么时候需要用到单例模式?


作者: 莫道荣    时间: 2013-3-5 22:27
我就说说我的理解吧:
问题一:声明私有的构造函数,是为了防止被其他类调用,否则的话,单例就不成立了。
问题二:开发单例的时候,主要是注意线程安全,即要保证在多线程运行的情况下,也不会发生线程同时访问一个变量的情况,所以,一般可以考虑为方法加"sychronized".
问题三:单例模式我知道的有懒汉式,和饱汉式。
问题四:这个还没有完全理解。
作者: 文密    时间: 2013-3-5 22:37
private Test(){} 私有化构造函数就是让其他程序无法创建该类对象
懒汉式
   class Single
   {
    private static Single s=null;
    private Single(){}  //让对象不可以初始化
     public static Single getInstance()
     {
       if(s==null)
       {
        s=new Single();
      
       ]
        return s;
      }
   }
懒汉式:是方法被调用时才对对象初始化,也叫做对象的延时加载
Single类进内存时,对象还没有存在,只有调用了getInstance()方法时,才建立对象
  懒汉式在多线程中会出不安全
它解决的问题是保证一个类在内存中的对象唯一性

作者: amen0205    时间: 2013-3-5 22:39
本帖最后由 门文通 于 2013-3-5 22:45 编辑

1   构造函数私有  是为了不让其他类创建对象,因为单例的意思就是一个类只能有一个对象。我定义好了  你拿去用  想再建个,noway。
2  关于多线程的问题,是需要加锁,这只是对懒汉式而言。
3  是分为懒汉式  你的第一种   和  饿汉式   你写的第二种
4  1中就说了是为了使一个类只有一个对象。举个例子:你有一个想法?你写成了一本书,别人要想看 ,就找你借,你可以借给甲,也可以借给乙,但有人想用你的方法再写出一本来,不行,他们不知道你的想法是什么,他们操作的只能是那一本书。

我们编程的时候会用 饿汉式  因为 Single  s = new Single(); 只有一句话。而懒汉式  执行  if(s=null)  s=new Single();  若在多线程中执行完if  一个线程停下了,又近来一个线程 创建了一个对象,那当第一个线程醒来时会继续执行又创建一个对象,那就不是单例设计模式了.所以不行 。

建议你还是去看看毕老师 第6天的视频。
作者: 王亚东    时间: 2013-3-5 23:00
问题一:问题是私有的构造函数,我不明白为什么一定要有个私有的构造函数?大家帮  忙看看!
    构造方法私有,这样外界就不可以通过new来创建对象了,并且私有是必须的,如果不写构造函数,编译器会默认super(),从父类(Object)继承。
问题二:在开发单例模式中有那些是需要注意的地方?比如构造方法之类的要注意什 么?
    构造方法私有就好了,楼上说的线程安全问题,使用饿汉式就好了,就是你在网上看到的那个,类一加载就自己初始化一个对象。
    还有一点就是,static变量和方法。
问题三:单利模式有几种形式?能不能给个例子?听说有懒汉式什么的?
    我就知道所谓的饿汉式,懒汉式。饿汉式就是上面说的,意思很明确,上来就初始化,就像饿汉;而第二种就是你写的那种,什么时候用才初始化,所以说是懒汉嘛。。但是这时就要注意线程安全了。
问题四:什么时候需要用到单例模式?
    一般工具类需要用到单例模式。总之,看需要,如若一个类只需要创建一个一次对象就用单例模式。


作者: 夏晓彤    时间: 2013-3-6 00:19
我来补充下
单例设计模式是解决一个类在内存中只存在一个对象,想要保证唯一
1。为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象,所有要将构造函数私有化
2为了让其他程序可以访问到该类对象,只好创建一个本类对象,
3为了方便其他程序可以访问该类对象,需要提供一个方法可以获取带该类对象
因为方法有两中调用方式,对象调用方法和类名调用方法,因为单模式,所有不能通过对象调用,所一要注意把方法顶一次static修饰,被访问的成员变量也必须是static类型,
懒汉是会出现线程同时访问一个变量的情况,所以要使用到sychronized".

什么时候用到单列
第一、控制资源的使用,通过线程同步来控制资源的并发访问;
第二、控制实例产生的数量,达到节约资源的目的。比如只想要有一个东西,例如:QQ聊天和一个朋友聊天,只打开一个对话框不管点击多少次还是一个,这样的效果我们就需要了。
作者: wodeairenw    时间: 2013-3-6 00:29
问题一:问题是私有的构造函数,我不明白为什么一定要有个私有的构造函数?大家帮  忙看看!
答:构造函数是私有函数的话,除了类自己的方法之外,其他类不能构造这个类的实例。一般来说,类做出来就是让其他类使用的,而使用一个类必须先构造它的实例。所以一般情况下,构造函数如果是私有函数,其他类要使用它就很困难了。
构造函数为私有的类有这样的特点:

<1>不能实例化:因为实例化时类外部无法访问其内部的私有的构造函数;

<2>不能继承:同<1>;

所以它可以控制用户实例化一个类对象。

问题二:在开发单例模式中有那些是需要注意的地方?比如构造方法之类的要注意什 么?
答:毕老师第六天的视屏中讲到的多线程方面的问题,是用你所给出的代码(懒汉式)关于CPU切换时当前程序A停止会使程序停住,可以加锁解决(会降低效率)或者双重判断解决。


问题三:单利模式有几种形式?能不能给个例子?听说有懒汉式什么的?
答:毕老师第六天的视屏中讲到两种形式,懒汉式(你所写的代码)和饿汉式(就是你在网上查到的那份代码)。懒汉式就是先在方法去里面建立判断条件条件符合才在堆内存中开辟空间建立实例化对象;而饿汉式就是一使用外部类中的主函数一调用饿汉式类中所提供的获取实例化的函数方法就马上在堆内存中创建对象
问题四:什么时候需要用到单例模式?
答:(我也是新手,这个是在网上查到的希望可以帮助你)
       第一、控制资源的使用,通过线程同步来控制资源的并发访问;
       第二、控制实例产生的数量,达到节约资源的目的。
       第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。
                  
       比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源

作者: 谢洋    时间: 2013-3-6 00:59
我想你是理解错了,先了解一下类加载的过程:
1、当我们要创建对象时,类加载器把该类的字节码加载到内存中,而这些字节码的内容就是该类的所有成分(包括静态的,非静态的成员或方法)
2,new 对象时,仅是把对象非静态成员变量,方法的引用,静态方法的引用,存放到堆内存中,正因为对象中有了方法的引用(地址)才能找到字节码中方法;
3,每当对象调用非静态方法时,JVM都会从字节码中根据对象传过来的方法的引用,找到该方法并copy到栈内存中,
并且该方法指向调用它的对象,以供对象使用,当用完后,该方法会被销毁(这就是所谓每次调用都被加载)。
4,其实静态的调用跟非静态的相似的,JVM根据对象或该类传过的来的静态方法的引用,找到该静态方法,并且是直接调用的,没什么copy动作。
(这就是只加载一次的说法)

作者: 江华    时间: 2013-3-6 01:10
前言:
java 是一个完全面向对象的编程语言。
所以,你在编程的时候,思想也要跟随java语言的思想特点,去写程序,只有这样写出来的程序,java虚拟机解释起来会更好。

问题一:问题是私有的构造函数,我不明白为什么一定要有个私有的构造函数?大家帮  忙看看!
        分析:  从这个问题,可以看出一下内容:
                1、你对构造函数的作用不太理解。
                2、私有 这个权限的作用,细分的话,就是你对权限的意义不是特别明白。
        解答:
                构造函数:
                        (个人理解)
                        举例说明,建大厦,你要有设计图,没有设计图,你也就不知道你要建什么玩意了。
                                大厦是一个对象,设计图就是这个对象的构造方法。只有有了构造方法,才能建造出对象。
                私有化构造函数:
                                你盖了一座大厦,盖成后,如果你把大厦的设计图纸自己保存起来,
                        问题1:        请问,其他人想建造同样的大厦,能建造?
                                同样,如果你把建造方法发布在网上,其他人可以随意浏览,
                        问题2:        请问,其他人想建造同样的大厦,能建造?
                       
                        回答完问题1和问题2,是否可以得出这么一个结论:
                        我想让其他人随意建造一个对象,那就把构造方法共享出去。
                        反之,只想建造一次,那就把构造方法私有化。
                                ---------------一下内容和上边的问题没有太大关系,只是一个扩展说明-------------------------------
                                --注意:这里建造次数的地方会有一个问题。
                                --你把设计图纸个藏起来,其他人不能建造同样的大厦,但是,图纸是在你自己的手里,
                                --你可以根据自己的需求建立多个一样的大厦
                                ------------------------------------------------------------------------------------------------       
问题二:在开发单例模式中有那些是需要注意的地方?比如构造方法之类的要注意什 么? ,
                分析:单例模式,就是只创建一次一个对象。
                        注意这里的两个“一”。
                        单进程下,饿汉式和懒汉式都没有什么问题。
                        但是在多进程下,懒汉式就会出现问题。
                       
                        private static Person p=new person();
                        public Person getPerson()
                        {
                                if (p==null)
                                        p=new person();
                                return p;
                        }
                        如果进程1,执行到 if(p=null) 语句判断完成后,该执行下边的“p=new person();”语句时,失去了系统执行权限,进程2这个时候进来了,
                        执行完流程,p就会有一个对象,而这个时候进程1获得执行权,它接着执行,就会再次创建对象。这样就创建两个对象。失去了单例模式的意义。
                       
                        推荐用饿汉式
                        private static Person p=new person();
                        public Person getPerson()
                        {
                                return p;
                        }
                       
                        另一个说法,言多必失!
                        ---------以下内容是在网上看到的,没遇到过也没有自己研究,如有不对敬请修正---------------
                        据说,饿汉式也不是特别安全的
                        如果把饿汉式放进代码同步块内,会出现一些问题。
                        具体情况,请高手解答!
                        --------------------------------------------------------------------------

问题三:单利模式有几种形式?能不能给个例子?听说有懒汉式什么的?

                        就我知道的单例模式就两种。
                       
问题四:什么时候需要用到单例模式?
                请参照你的 问题一 的答案





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2