关于Java单例模式的一点问题

群居的山羊 2017-03-15 01:17:43
今天看了Java的单例模式,个人理解就是无论创建多少类的实例,他们始终都与该类自己创建的实例指向同一地址。这里我有一个问题,就是在多个页面互相交互(比如说安卓多个Activity控制同一个实例)。这种情况用static把实例绑定在Activity中再访问也能做到类似的效果(当然,我指的仅仅是可以多个活动操作同一个实例这一点)这种情况应该用static绑定还是用单例模式呢,求指教,
...全文
186 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
群居的山羊 2017-03-16
  • 打赏
  • 举报
回复
引用 4 楼 逗泥丸的平方的回复:
[quote=引用 1 楼 Tomake 的回复:] 很简单啊,虽然static也能实现类似单例模式的功能,但是static作为一个静态方法,在加载类的时候就被加载到内存中,不管你有没有用到,都是很占内存的,static一多就很消耗内存。所以尽量都是用单例呗!
是静态成员还是静态方法,把我说糊涂了... 而且.. 就算你单例模式也离不开静态方法呀.. 要不然怎么创建对象.[/quote] 对啊,我之后看也有这种感觉,这个实际上不是还是相当于绑定在这个类本身么……可能单例模式的目的主要是为了不被胡乱创建new对象而不是共享一个对象吧
逗泥丸的平方 2017-03-16
  • 打赏
  • 举报
回复
引用 2 楼 zs808 的回复:
首先,我要指出你理解上的一个偏差,单例模式并不是代表“无论创建多少类的实例,他们始终都与该类自己创建的实例指向同一地址”这句话是错误的,对象每一次通过new进行“创建”,都必然会指向一个新的内存地址,这在JVM规范里有提出。 单例模式,作为对象的创建型模式,它的作用就是限制对象构造函数的访问,从而限制对象的数量,使其在整个程序执行期内只会有一个副本。每次对该类型对象操作前,都会取这个副本来进行操作,而不是每一次都是创建一个对象出来,然后对其操作。 实现单例的方式有很多种,在JAVA中,实现单例要用static方法或者static变量,这是由Java变量的作用域与生命周期所决定的。至于选用static方法还是static变量,则需要根据具体的需求来进行取舍。下面分别举个例子:
public class Main {
	String hello = "Hello";
	
	//静态变量实现单例,适用于懒汉模式创建
	static final Main Instance = new Main();
	
	static Main _instance = null;
	//静态方法实现单例,适用于饿汉模式创建
	static Main newInstance(){
		if(_instance == null){
			synchronized (Main.class) {
				if(_instance == null){
					_instance = new Main(); //这里调用Main的构造函数
				}
			}
		}
		return _instance;
	}
	
	Main(){
		System.out.println("Main class created");
	}
	
	public static void main(String[] args) throws InterruptedException {
		System.out.println("App start");
		Main sigCls = Main.Instance;  //static单例变量的访问
		System.out.println(sigCls.hello);
		sigCls = Main.newInstance();  //static单例方法的访问
		System.out.println(sigCls.hello);
	}
}
可以看到,使用static变量的方式来进行单例实现,对象的创建写在方法之外,并且对象会在类加载的时候进行创建(也就是懒汉模式),不是很灵活(创建时只能访问static变量或者方法)。使用static方法的方式来进行单例实现,对象的创建写在方法之内,并且对象只会在调用该方法时进行创建(也就是饿汉模式),这种写法比较复杂,但是很灵活。 ============= 好啦,废话不说了,对于你说的“安卓多个Activity控制同一个实例”的单例的话,如果你这个实例的创建代价比较大,就用static方法来创建,如果创建代价不是很大的话,就用static变量就行啦
这里对代价的说明好像不是很清楚... (懒汉,饿汉的问题lz已经指出来了) 就我的理解来看,空间代价大的倾向于尽量晚加载,而时间代价大的则倾向于尽量早加载.. 当然多数时候感觉并不需要管这种事情... 最后推荐一种枚举类的方式来做单例, 这是目前看起来比较diao的一种方式
逗泥丸的平方 2017-03-16
  • 打赏
  • 举报
回复
引用 1 楼 Tomake 的回复:
很简单啊,虽然static也能实现类似单例模式的功能,但是static作为一个静态方法,在加载类的时候就被加载到内存中,不管你有没有用到,都是很占内存的,static一多就很消耗内存。所以尽量都是用单例呗!
是静态成员还是静态方法,把我说糊涂了... 而且.. 就算你单例模式也离不开静态方法呀.. 要不然怎么创建对象.
群居的山羊 2017-03-15
  • 打赏
  • 举报
回复
引用 2 楼 zs808的回复:
首先,我要指出你理解上的一个偏差,单例模式并不是代表“无论创建多少类的实例,他们始终都与该类自己创建的实例指向同一地址”这句话是错误的,对象每一次通过new进行“创建”,都必然会指向一个新的内存地址,这在JVM规范里有提出。 单例模式,作为对象的创建型模式,它的作用就是限制对象构造函数的访问,从而限制对象的数量,使其在整个程序执行期内只会有一个副本。每次对该类型对象操作前,都会取这个副本来进行操作,而不是每一次都是创建一个对象出来,然后对其操作。 实现单例的方式有很多种,在JAVA中,实现单例要用static方法或者static变量,这是由Java变量的作用域与生命周期所决定的。至于选用static方法还是static变量,则需要根据具体的需求来进行取舍。下面分别举个例子:
public class Main {
	String hello = "Hello";
	
	//静态变量实现单例,适用于懒汉模式创建
	static final Main Instance = new Main();
	
	static Main _instance = null;
	//静态方法实现单例,适用于饿汉模式创建
	static Main newInstance(){
		if(_instance == null){
			synchronized (Main.class) {
				if(_instance == null){
					_instance = new Main(); //这里调用Main的构造函数
				}
			}
		}
		return _instance;
	}
	
	Main(){
		System.out.println("Main class created");
	}
	
	public static void main(String[] args) throws InterruptedException {
		System.out.println("App start");
		Main sigCls = Main.Instance;  //static单例变量的访问
		System.out.println(sigCls.hello);
		sigCls = Main.newInstance();  //static单例方法的访问
		System.out.println(sigCls.hello);
	}
}
可以看到,使用static变量的方式来进行单例实现,对象的创建写在方法之外,并且对象会在类加载的时候进行创建(也就是懒汉模式),不是很灵活(创建时只能访问static变量或者方法)。使用static方法的方式来进行单例实现,对象的创建写在方法之内,并且对象只会在调用该方法时进行创建(也就是饿汉模式),这种写法比较复杂,但是很灵活。 ============= 好啦,废话不说了,对于你说的“安卓多个Activity控制同一个实例”的单例的话,如果你这个实例的创建代价比较大,就用static方法来创建,如果创建代价不是很大的话,就用static变量就行啦
谢谢你详细的讲解,感觉疑惑都解决了,只是你那个懒汉模式和饿汉模式的顺序是不是弄反了?饿汉模式才是在类加载时就创建对象吧
zs808 2017-03-15
  • 打赏
  • 举报
回复
首先,我要指出你理解上的一个偏差,单例模式并不是代表“无论创建多少类的实例,他们始终都与该类自己创建的实例指向同一地址”这句话是错误的,对象每一次通过new进行“创建”,都必然会指向一个新的内存地址,这在JVM规范里有提出。 单例模式,作为对象的创建型模式,它的作用就是限制对象构造函数的访问,从而限制对象的数量,使其在整个程序执行期内只会有一个副本。每次对该类型对象操作前,都会取这个副本来进行操作,而不是每一次都是创建一个对象出来,然后对其操作。 实现单例的方式有很多种,在JAVA中,实现单例要用static方法或者static变量,这是由Java变量的作用域与生命周期所决定的。至于选用static方法还是static变量,则需要根据具体的需求来进行取舍。下面分别举个例子:
public class Main {
	String hello = "Hello";
	
	//静态变量实现单例,适用于懒汉模式创建
	static final Main Instance = new Main();
	
	static Main _instance = null;
	//静态方法实现单例,适用于饿汉模式创建
	static Main newInstance(){
		if(_instance == null){
			synchronized (Main.class) {
				if(_instance == null){
					_instance = new Main(); //这里调用Main的构造函数
				}
			}
		}
		return _instance;
	}
	
	Main(){
		System.out.println("Main class created");
	}
	
	public static void main(String[] args) throws InterruptedException {
		System.out.println("App start");
		Main sigCls = Main.Instance;  //static单例变量的访问
		System.out.println(sigCls.hello);
		sigCls = Main.newInstance();  //static单例方法的访问
		System.out.println(sigCls.hello);
	}
}
可以看到,使用static变量的方式来进行单例实现,对象的创建写在方法之外,并且对象会在类加载的时候进行创建(也就是懒汉模式),不是很灵活(创建时只能访问static变量或者方法)。使用static方法的方式来进行单例实现,对象的创建写在方法之内,并且对象只会在调用该方法时进行创建(也就是饿汉模式),这种写法比较复杂,但是很灵活。 ============= 好啦,废话不说了,对于你说的“安卓多个Activity控制同一个实例”的单例的话,如果你这个实例的创建代价比较大,就用static方法来创建,如果创建代价不是很大的话,就用static变量就行啦
Tomake 2017-03-15
  • 打赏
  • 举报
回复
很简单啊,虽然static也能实现类似单例模式的功能,但是static作为一个静态方法,在加载类的时候就被加载到内存中,不管你有没有用到,都是很占内存的,static一多就很消耗内存。所以尽量都是用单例呗!

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧