精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-05-18
最后修改:2011-05-18
nianien 写道 zhang34082 写道 第三种与第一种 是一样的机制,都是通过静态块来初始化的"
怎么能是一样的呢? 都说了实例化的时间不一样 第一种,只要你第一次引用了类,都会触发单例对象的实例化 而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的 类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。 public static void main(String[] args) { SingleTon instance = SingleTon .getInstance();// 在这个地方设断点 } 可以通过这个在测试。是否是延迟加载的 |
|
返回顶楼 | |
发表时间:2011-05-18
zhang34082 写道 littcai 写道 第一种是延迟加载的,优
不是延迟加载的,都是类加载的时候 初始化实例变量的,没区别 在类加载的时候,静态变量与静态块 从上而下逐个执行的。 |
|
返回顶楼 | |
发表时间:2011-05-18
zhang34082 写道 nianien 写道 zhang34082 写道 第三种与第一种 是一样的机制,都是通过静态块来初始化的"
怎么能是一样的呢? 都说了实例化的时间不一样 第一种,只要你第一次引用了类,都会触发单例对象的实例化 而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的 类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。 public static void main(String[] args) { SingleTon instance = SingleTon .getInstance();// 在这个地方设断点 } 可以通过这个在测试。是否是延迟加载的 public class SingleTon { private SingleTon(){} public static SingleTon getInstance() { return SingleTonHolder.instance; } static class SingleTonHolder{ private static SingleTon instance=new SingleTon(); } } 你敢实际测试一下么? 你不调用,它会实例化? |
|
返回顶楼 | |
发表时间:2011-05-18
最后修改:2011-05-18
nianien 写道 zhang34082 写道 nianien 写道 zhang34082 写道 第三种与第一种 是一样的机制,都是通过静态块来初始化的"
怎么能是一样的呢? 都说了实例化的时间不一样 第一种,只要你第一次引用了类,都会触发单例对象的实例化 而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的 类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。 public static void main(String[] args) { SingleTon instance = SingleTon .getInstance();// 在这个地方设断点 } 可以通过这个在测试。是否是延迟加载的 public class SingleTon { private SingleTon(){} public static SingleTon getInstance() { return SingleTonHolder.instance; } static class SingleTonHolder{ private static SingleTon instance=new SingleTon(); } } 你敢实际测试一下么? 你不调用,它会实例化? 多的俺不说了,如果你觉得他是延迟加载的,你提供测试方法出来,或者说下静态类、嵌套类中静态实例在类加载的时候是怎么加载的 |
|
返回顶楼 | |
发表时间:2011-05-18
最后修改:2011-05-18
nianien 写道 个人认为下面是Java实现的最优的单例模式
这种实现方法采用内部静态类, 只在第一次调用getInstance方法的时候才实例化单例对象 如果不调用,就不会进行单例对象的实例化, 因此,既实现了延迟实例化,又不需要线程同步 引用 public class SingleTon { private SingleTon(){} public static SingleTon getInstance() { return SingleTonHolder.instance; } private static class SingleTonHolder{ private static SingleTon instance=new SingleTon(); } } 下面这种单例模式是应用最多的,同样不存在线程同步的问题 但是,不能实现延迟实例化 引用 public class SingleTon { private SingleTon(){} private static SingleTon s=new SingleTon(); public static SingleTon getInstance() { return s; } } 这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的 引用 public class SingleTon { private SingleTon(){} private static SingleTon s; static { s=new SingleTon(); } public static SingleTon getInstance() { return s; } } 下面这种就是 还有两种解决方案,不在本帖讨论范围之内 1.采用synchronized的关键字同步getInstance方法 2.采用synchronized的关键字同步代码段,双重是否为空的判断 下面是测试结果,以证明本人想法的正确性: public class SingleTon { static { System.out.println("悲催了,被加载了!"); } private SingleTon() { System.out.println("悲催了,被实例化了!"); } public static SingleTon getInstance() { return SingleTonHolder.instance; } public static void otherMethod() { System.out.println("悲催了,调用其他方法了!"); } private static class SingleTonHolder { private static SingleTon instance = new SingleTon(); } } public class Test { public static void main(String[] args) throws ClassNotFoundException { Class.forName("com.lining.SingleTon"); SingleTon.otherMethod(); SingleTon.getInstance(); } } output: 悲催了,被加载了! 悲催了,调用其他方法了! 悲催了,被实例化了! |
|
返回顶楼 | |
发表时间:2011-05-18
zhang34082 写道 nianien 写道 zhang34082 写道 nianien 写道 zhang34082 写道 第三种与第一种 是一样的机制,都是通过静态块来初始化的"
怎么能是一样的呢? 都说了实例化的时间不一样 第一种,只要你第一次引用了类,都会触发单例对象的实例化 而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的 类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。 public static void main(String[] args) { SingleTon instance = SingleTon .getInstance();// 在这个地方设断点 } 可以通过这个在测试。是否是延迟加载的 public class SingleTon { private SingleTon(){} public static SingleTon getInstance() { return SingleTonHolder.instance; } static class SingleTonHolder{ private static SingleTon instance=new SingleTon(); } } 你敢实际测试一下么? 你不调用,它会实例化? 多的俺不说了,如果你觉得他是延迟加载的,你提供测试方法出来,或者说下静态类、嵌套类中静态实例在类加载的时候是怎么加载的 测试结果出来了,你还有什么话说? 唉,眼高手低的人~~~~~~ |
|
返回顶楼 | |
发表时间:2011-05-18
最后修改:2011-05-18
nianien 写道 下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化 引用 public class SingleTon { private SingleTon(){} private static SingleTon s=new SingleTon(); public static SingleTon getInstance() { return s; } } 这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的 引用 public class SingleTon { private SingleTon(){} private static SingleTon s; static { s=new SingleTon(); } public static SingleTon getInstance() { return s; } } 上下两份代码编译后的字节码一模一样, 何来上面一种“但是,不能实现延迟实例化” 而下面一种“虽然能够延迟单例对象的实例化” 也就是说: private static SingleTon s=new SingleTon(); 完全等价于: private static SingleTon s; static { s=new SingleTon(); } 静态变量的初始化发生在 类被加载的时候(缺省情况下,被加载的类会在加载时被初始化,除非明确指定延迟初始化), public static Class<?> forName(String name, boolean initialize, ClassLoader loader) |
|
返回顶楼 | |
发表时间:2011-05-18
nianien 写道 zhang34082 写道 第三种与第一种 是一样的机制,都是通过静态块来初始化的
怎么能是一样的呢? 都说了实例化的时间不一样 第一种,只要你第一次引用了类,都会触发单例对象的实例化 而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的 static是什么?哪来的延迟。 |
|
返回顶楼 | |
发表时间:2011-05-18
最后修改:2011-05-18
nianien 写道 引用 public class SingleTon { private SingleTon(){} public static SingleTon getInstance() { return SingleTonHolder.instance; } private static class SingleTonHolder{ private static SingleTon instance=new SingleTon(); } } 这种方式下的确 是延迟到getInstance()方法被调用的时候才实例化new SingleTon(); nianien 写道 下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化 引用 public class SingleTon { private SingleTon(){} private static SingleTon s=new SingleTon(); public static SingleTon getInstance() { return s; } } 这种方式下new SingleTon();是在SingleTon类被加载的时候才初始化的,SingleTon类被加载的时机是 该类第一次被引用的时候。所以,什么时候加载不确定。 但一般引用SingleTon类的代码被执行的时候,也就是需要使用的时候了,所以实质上也有延迟的效果。 比如下面的代码: public class SingleTon { private static SingleTon s = new SingleTon(); public static SingleTon getInstance() { return s; } static { System.out.println("悲催了,被加载了!"); } private SingleTon() { System.out.println("悲催了,被实例化了!"); } } public class Test { public static void main(String[] args) throws ClassNotFoundException { Class.forName("my.SingleTon", false, Test.class.getClassLoader()); System.out.println("做点其他事情..."); SingleTon.getInstance(); } } Test类main方法的第一行加载SingleTon类,但不会初始化SingleTon。 SingleTon类被初始化是 直到调用SingleTon.getInstance();方法的时候。 所以,这种方法也是具有延迟加载效果的。 |
|
返回顶楼 | |
发表时间:2011-05-18
sswh 写道 nianien 写道 下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化 引用 public class SingleTon { private SingleTon(){} private static SingleTon s=new SingleTon(); public static SingleTon getInstance() { return s; } } 这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的 引用 public class SingleTon { private SingleTon(){} private static SingleTon s; static { s=new SingleTon(); } public static SingleTon getInstance() { return s; } } 上下两份代码编译后的字节码一模一样, 何来上面一种“但是,不能实现延迟实例化” 而下面一种“虽然能够延迟单例对象的实例化” 也就是说: private static SingleTon s=new SingleTon(); 完全等价于: private static SingleTon s; static { s=new SingleTon(); } 静态变量的初始化发生在 类被加载的时候(缺省情况下,被加载的类会在加载时被初始化,除非明确指定延迟初始化), public static Class<?> forName(String name, boolean initialize, ClassLoader loader) 静态代码块和静态成员变量加载是有先后顺序的好不好? public class InitDemo { private static Demo d1 = new Demo(1); private static Demo d2 = new Demo(2); private static Demo d3 = new Demo(3); static { d1 = new Demo(0); d1 = new Demo(0); d1 = new Demo(0); } public static void main(String[] args) throws ClassNotFoundException { System.out.println(); } } class Demo { public Demo(int count) { System.out.println(count); } } 从测试结果你可以看到,静态代码块执行顺序要晚于静态字段,因此,我们常用静态代码块改写初始值,字段默认初始值为null,执行静态代码块就是改写null值,它并不是最初的赋值 |
|
返回顶楼 | |