黑马程序员技术交流社区

标题: 单例设计模式的小问题 [打印本页]

作者: 芦青    时间: 2013-4-1 18:13
标题: 单例设计模式的小问题
本帖最后由 芦青 于 2013-4-1 21:21 编辑

class Singleo
{
        
        private Single(){}
        private static Single s=new Single();
        public static Single getInstance()
        {
                return s;
        }
}

以上是个单例设计,我的疑惑是内存情况:当类被加载的时候,静态变量和静态方法都会被加载,这里是当类文件里静态变量和静态方法该加载的全部加载到方法区以后 才执行 Single s=new Single()  开辟堆空间 ...还是一加载到成员变量的时候就执行new single()开辟堆空间,然后在加载静态方法?  我感觉加载的时候不应该执行任何的语句啊..

作者: 王亚东    时间: 2013-4-1 18:30
通过测试结果:
aa
null
static
在静态代码块执行之前,就执行了构造方法,所以应该是“一加载到成员变量的时候就执行new single()开辟堆空间”
  1. public class Demo03 {
  2. public static void main(String[] args) {
  3.   Single.getInstance();
  4. }
  5. }
  6. class Single{
  7. private static Single s = new Single();
  8. static{
  9.   System.out.println("static");
  10. }
  11. private Single(){
  12.   System.out.println("aa");
  13.   System.out.println(s);
  14. }
  15. public static Single getInstance(){
  16.   return s;
  17. }
  18. }
复制代码

作者: 张君    时间: 2013-4-1 18:35
当类被加载的时候,静态变量和静态方法都会被加载, 而建立对象是在运行的时候才在堆内存开辟空间
作者: 芦青    时间: 2013-4-1 18:36
王亚东 发表于 2013-4-1 18:30
通过测试结果:
aa
null

确定? 那你这测试结果,不就相当于对象比静态方法和静态代码块还先存在了?:funk:
作者: whs_nk    时间: 2013-4-1 18:39
是当类文件里静态变量和静态方法该加载的全部加载到方法区以后 才执行 Single s=new Single()  开辟堆空间的,静态的首先存在,开辟堆空间后,将实例在内存中的地址给了s,静态变量的引用指向了对象,以后对象的获得,都是通过这个引用传递的,单例也就得以实现。另外,觉得静态方法的加载,并不是就代表静态方法的执行,调用的时候才是真正的执行吧,也就是Single anotherOne = Single.getInstance();才真正执行。欢迎指正哦
作者: 芦青    时间: 2013-4-1 18:40
张君 发表于 2013-4-1 18:35
当类被加载的时候,静态变量和静态方法都会被加载, 而建立对象是在运行的时候才在堆内存开辟空间 ...

虾米? 是运行的时候,jvm才会去加载类,如果用到类中内容的话..
作者: 芦青    时间: 2013-4-1 18:50
whs_nk 发表于 2013-4-1 18:39
是当类文件里静态变量和静态方法该加载的全部加载到方法区以后 才执行 Single s=new Single()  开辟堆空间 ...

有道理,不过你认为的Single anotherOne = Single.getInstance()这句话,正是因为调用到了,用到了 Single类的内容 jvm才去加载 Single类的 .. 不存在着,调用的时候才是真正的执行,不然jvm干嘛去加载..我认为应该是jvm 读到Single.getInstance()这句话的时候,瞬间完成加载 Single类并去调用 Single类中的 getInstance()方法..你认为呢?
作者: 王亚东    时间: 2013-4-1 19:04
芦青 发表于 2013-4-1 18:36
确定? 那你这测试结果,不就相当于对象比静态方法和静态代码块还先存在了? ...

你可以运行下这个代码,确实是先创建了对象,然后才加载的静态代码块
  1. public class Demo01 {
  2.         public static void main(String[] args) throws ClassNotFoundException {
  3.                 Class.forName("Single");
  4.         }
  5. }

  6. class Single {
  7.         private static Single s = new Single();
  8.         static {
  9.                 System.out.println("static");
  10.         }

  11.         private Single() {
  12.                 System.out.println("aa");
  13.                 try {
  14.                         Thread.sleep(1000);
  15.                 } catch (InterruptedException e) {
  16.                         e.printStackTrace();
  17.                 }
  18.                 System.out.println(s);
  19.         }

  20.         public static Single getInstance() {
  21.                 return s;
  22.         }
  23. }
复制代码
主要是因为单例是在类内部自己创建的对象,而且还是在给静态属性赋值的时候
作者: 芦青    时间: 2013-4-1 19:15
王亚东 发表于 2013-4-1 19:04
你可以运行下这个代码,确实是先创建了对象,然后才加载的静态代码块主要是因为单例是在类内部自己创建的 ...

谢谢,你的意思是不是:在饿汉式下,加载 Single类的时候,加载到静态成员这一步的时候,就先会去创建对象空间,创建完以后才继续加载静态和非静态方法,以及构造代码块等..?
作者: 王亚东    时间: 2013-4-1 19:38
芦青 发表于 2013-4-1 19:15
谢谢,你的意思是不是:在饿汉式下,加载 Single类的时候,加载到静态成员这一步的时候,就先会去创建对 ...

类中所有静态的一般都是按照从上到下的顺序加载(提前被使用到例外)
创建对象后,如果使用这个对象调用非静态方法,那么这个非静态会在其他静态方法之前加载
(也许是在创建对象的时候就加载了?这个有待求证)
构造代码块在构造方法之前执行




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