论坛首页 Java企业应用论坛

非线程同步机制下线程安全的单例模式——最优的单例模式

浏览 15273 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-05-18  
nianien 写道

静态代码块和静态成员变量加载是有先后顺序的好不好?
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值,它并不是最初的赋值


静态代码块执行顺序要晚于静态字段

这句话不准确。静态代码的初始化顺序取决于 声明的顺序,没有绝对的 静态代码块晚于静态字段。

看下面的代码:
public class InitDemo {
	static {
		d1 = new Demo(4);
	}
	private static Demo d1 = new Demo(1);

	static {
		d1 = new Demo(5);
	}
	private static Demo d2 = new Demo(2);

	public static void main(String[] args) throws ClassNotFoundException {
		System.out.println();
	}

}

class Demo {
	public Demo(int count) {
		System.out.println(count);
	}
}


其实,本质上来说:

private static Demo d1 = new Demo(1);


完全等价于:
	private static Demo d1 = null;
	static {
		d1 = new Demo(1);
	}


它们只是两种不同的书写方法而已。不止静态变量,实例变量也是一样。

实例变量的初始化可以以3种形式定义,但编译器编译的时候,会把各种形式的初始化语句按出现顺序放到构造函数中。

public class InitDemo {
	Map buf = new HashMap();
	{
		buf.put("aaa", "bbb");
	}
	String s2;
	public InitDemo() {
		s2 = "ddd";
	}
}


等价于:
public class InitDemo {
	Map buf;
	String s2;
	public InitDemo() {
		buf = new HashMap();
		buf.put("aaa", "bbb");
		s2 = "ddd";
	}
}


0 请登录后投票
   发表时间:2011-05-18  
sswh 写道
nianien 写道

静态代码块和静态成员变量加载是有先后顺序的好不好?
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值,它并不是最初的赋值


静态代码块执行顺序要晚于静态字段

这句话不准确。静态代码的初始化顺序取决于 声明的顺序,没有绝对的 静态代码块晚于静态字段。

看下面的代码:
public class InitDemo {
	static {
		d1 = new Demo(4);
	}
	private static Demo d1 = new Demo(1);

	static {
		d1 = new Demo(5);
	}
	private static Demo d2 = new Demo(2);

	public static void main(String[] args) throws ClassNotFoundException {
		System.out.println();
	}

}

class Demo {
	public Demo(int count) {
		System.out.println(count);
	}
}


其实,本质上来说:

private static Demo d1 = new Demo(1);


完全等价于:
	private static Demo d1 = null;
	static {
		d1 = new Demo(1);
	}


它们只是两种不同的书写方法而已。不止静态变量,实例变量也是一样。

实例变量的初始化可以以3种形式定义,但编译器编译的时候,会把各种形式的初始化语句按出现顺序放到构造函数中。

public class InitDemo {
	Map buf = new HashMap();
	{
		buf.put("aaa", "bbb");
	}
	String s2;
	public InitDemo() {
		s2 = "ddd";
	}
}


等价于:
public class InitDemo {
	Map buf;
	String s2;
	public InitDemo() {
		buf = new HashMap();
		buf.put("aaa", "bbb");
		s2 = "ddd";
	}
}



嗯,你说的对,以后得多向你学习了~
0 请登录后投票
   发表时间:2011-05-18  
[quote="sswh]
public static void main(String[] args) throws ClassNotFoundException { 
Class.forName("my.SingleTon", false, Test.class.getClassLoader()); 
System.out.println("做点其他事情..."); 
SingleTon.getInstance(); 
} 
} 

[quote name="kingkan"]
调用静态方法或属性不用实例化。
调用对象方法或属性肯定要实例化。


请问kingkan说法对不对?
我测试了一下,即使调用静态方法,静态代码块和静态字段都会初始化的
0 请登录后投票
   发表时间:2011-05-18  
nianien 写道
[quote="sswh]
public static void main(String[] args) throws ClassNotFoundException { 
Class.forName("my.SingleTon", false, Test.class.getClassLoader()); 
System.out.println("做点其他事情..."); 
SingleTon.getInstance(); 
} 
} 

[quote name="kingkan"]
调用静态方法或属性不用实例化。
调用对象方法或属性肯定要实例化。


请问kingkan说法对不对?
我测试了一下,即使调用静态方法,静态代码块和静态字段都会初始化的

关于Class.forName对一个类实例化时,static关键字修饰的变量初始化与否与类加载器有关,
默认forName0(className, true, ClassLoader.getCallerClassLoader());
如果为forName0(className, false, ClassLoader.getCallerClassLoader());那么就不会初始化类中的static变量
http://technoboy.iteye.com/blog/1005718
0 请登录后投票
   发表时间:2011-05-18  
在哪看过,最好的单例模式是只含一个元素的enum
0 请登录后投票
   发表时间:2011-05-18  
赵精龙 写道
在哪看过,最好的单例模式是只含一个元素的enum

给出代码来,学习一下~
0 请登录后投票
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道

[quote name="kingkan"]
调用静态方法或属性不用实例化。
调用对象方法或属性肯定要实例化。

请问kingkan说法对不对?
我测试了一下,即使调用静态方法,静态代码块和静态字段都会初始化的


好像kingkan说的意思是 类不用实例化也可以调用类的静态方法。
这个说法没错,但和你说的应该不是一个意思。

你说的“调用静态方法,静态代码块和静态字段都会初始化的”,没错,是这样的。

关于类的初始化,在《深入Java虚拟机》中这样描述:

引用

Java虚拟机在首次主动使用类型时初始化它们。只有6种活动被认为是主动使用:
创建类的新实例,
调用类中声明的静态方法,
操作类或者接口中声明的非常量静态字段,
调用Java API中特定的反射方法,
初始化一个类的子类,
以及指定一个类作为Java虚拟机启动时的初始化类。


大概意思是,基本上对类上静态字段、方法的操作都会导致类的初始化。
但除了一种特殊情况以外:
如果使用的是静态常量(static final),并且常量值是一个编译时常量表达式,
这时候不会导致类被初始化。


0 请登录后投票
   发表时间:2011-05-18  
nianien 写道
littcai 写道
第一种是延迟加载的,优

从多线程的角度考虑,会不会有并发问题呢?

SingleTon 类在系统启动后就已经创建好了,不会产生并发问题,你可以去了解下静态类
0 请登录后投票
   发表时间:2011-05-18  
huanglei7211 写道
nianien 写道
littcai 写道
第一种是延迟加载的,优

从多线程的角度考虑,会不会有并发问题呢?

SingleTon 类在系统启动后就已经创建好了,不会产生并发问题,你可以去了解下静态类

必须有并发问题。
0 请登录后投票
   发表时间:2011-05-18  
sswh 写道
nianien 写道

[quote name="kingkan"]
调用静态方法或属性不用实例化。
调用对象方法或属性肯定要实例化。

请问kingkan说法对不对?
我测试了一下,即使调用静态方法,静态代码块和静态字段都会初始化的


好像kingkan说的意思是 类不用实例化也可以调用类的静态方法。
这个说法没错,但和你说的应该不是一个意思。

你说的“调用静态方法,静态代码块和静态字段都会初始化的”,没错,是这样的。

关于类的初始化,在《深入Java虚拟机》中这样描述:

引用

Java虚拟机在首次主动使用类型时初始化它们。只有6种活动被认为是主动使用:
创建类的新实例,
调用类中声明的静态方法,
操作类或者接口中声明的非常量静态字段,
调用Java API中特定的反射方法,
初始化一个类的子类,
以及指定一个类作为Java虚拟机启动时的初始化类。


大概意思是,基本上对类上静态字段、方法的操作都会导致类的初始化。
但除了一种特殊情况以外:
如果使用的是静态常量(static final),并且常量值是一个编译时常量表达式,
这时候不会导致类被初始化。



再次向你致敬,你Java水平比我高,学习了~
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics