我们在编程中最常用的模式就是单例模式了,然而单例模式都用在什么场合?为什么不用静态方法而要用单例模式呢?要搞清这些问题,需要从静态方法和非静态方法的区别和联系说起。

一、静态方法常驻内存,非静态方法只有使用的时候才分配内存?

一般都认为是这样,并且怕静态方法占用过多内存而建议使用非静态方法,其实这个理解是错误的。

为什么会这样,先从内存分配开始说起:

托管堆的定义:对于32位的应用程序来说,应用程序完成进程初始化后,CLR将在进程的可用地址空间分配一块保留的地址空间,它是进程(每个进程可使用4GB)中可用地址空间上的一块内存区域,但并不对应任何物理内存,这块地址空间即是托管堆。

托管堆有分为多个区域,其中最重要的是垃圾回收堆(GC Heap)和加载堆(Loader Heap),GC
Heap用于存储对象实例,受GC管理;Loader Heap又分为High-Frequency Heap、Low-Frequency
Heap和Stub Heap,不同的堆上又存储不同的信息。Loader
Heap最重要的信息就是元数据相关的信息,也就是Type对象,每个Type在Loader Heap上体现为一个Method
Table(方法表),而Method Table中则记录了存储的元数据信息,例如基类型、静态字段、实现的接口、所有的方法等等。Loader
Heap不受GC控制,其生命周期为从创建到AppDomain卸载。(摘自《你必须知道的.Net》)

由此我们就明白了,静态方法和非静态方法,在内存里其实都放在Method Table里了,在一个类第一次被加载的时候,它会在Loader
Heap里把静态方法,非静态方法都写入Method Table中,而且Loader
Heap不受GC控制,所以一旦加载,GC就不会回收,直到AppDomain卸载

由此我们也明白了,静态方法和非静态方法,他们都是在第一次加载后就常驻内存,所以方法本身在内存里,没有什么区别,所以也就不存在”静态方法常驻内存,非静态方法只有使用的时候才分配内存“这个结论了。

二、静态方法和非静态方法的区别?

在内存中的区别是,非静态方法在创建实例对象时,因为属性的值对于每个对象都各不相同,因此在new一个实例时,会把这个实例属性在GC
Heap里拷贝一份,同时这个new出来的对象放在堆栈上,堆栈指针指向了刚才拷贝的那一份实例的内存地址上。而静态方法则不需要,因为静态方法里面的静态字段,就是保存在Method
Table里了,只有一份。

因此静态方法和非静态方法,在调用速度上,静态方法速度一定会快点,因为非静态方法需要实例化,分配内存,但静态方法不用,但是这种速度上差异可以忽略不计。

三、为什么要有非静态方法?

早期的结构化编程,几乎所有的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建c++,java,c#这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。

接下来继续思考,如果我们全部用静态方法,不用非静态方法,不是一样能实现功能吗?是的,没错,但是你的代码是基于对象,而不是面向对象的,因为面向对象的继承和多态,都是非静态方法。

第二个原因是为什么不建议都用静态方法,我们如果多线程的情况下,如果静态方法使用了一个静态字段,这个静态字段可以会被多个线程修改,因此说如果在静态方法里使用了静态变量,这就会有线程安全问题,当然了,就算不是多线程,因为静态字段只有一份,同样会有被其他地方修改的问题。

从这三点我们得出的结论如下:

一、 什么时候用静态方法,什么时候使用非静态方法?

既然静态方法和实例化方式的区分是为了解决模式的问题,如果我们考虑不需要继承和多态的时候,就可以使用静态方法,但就算不考虑继承和多态,就一概使用静态方法也不是好的编程思想。

从另一个角度考虑,如果一个方法和他所在类的实例对象无关,那么它就应该是静态的,否则就应该是非静态。因此像工具类,一般都是静态的。

二、 为什么使用单例模式而不用静态方法?

从面相对象的角度讲:

虽然都能实现目的,但是他们一个是基于对象,一个是面向对象的,就像我们不面相对象也能解决问题一样,面相对象的代码提供一个更好的编程思想。

如果一个方法和他所在类的实例对象无关,那么它就应该是静态的,反之他就应该是非静态的。如果我们确实应该使用非静态的方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式了。

比如说我们在系统运行时候,就需要加载一些配置和属性,这些配置和属性是一定存在了,又是公共的,同时需要在整个生命周期中都存在,所以只需要一份就行,这个时候如果需要我再需要的时候new一个,再给他分配值,显然是浪费内存并且再赋值没什么意义,所以这个时候我们就需要单例模式或静态方法去维持一份且仅这一份拷贝,但此时这些配置和属性又是通过面向对象的编码方式得到的,我们就应该使用单例模式,或者不是面向对象的,但他本身的属性应该是面对对象的,我们使用静态方法虽然能同样解决问题,但是最好的解决方案也应该是使用单例模式。

从功能上讲:

单例模式可以控制单例数量;可以进行有意义的派生;对实例的创建有更自由的控制;

三、其他:

数据库连接能不能做SingleTon?

如果是简单地把一个connection对象封存在单例对象中,这样是错误的,因此连接池里有多个链接可以用,如果使用SingleTon,那在WEB访问时,就只能用一个数据库链接,那不是死的很惨?

但是链接池可以使用单例模式,初始化的时候创建譬如100个connection对象,然后再需要的时候提供一个,用过之后返回到pool中,我们用单例模式,是保证连接池有且只有一个。

再举个例子,比如DAL层写好一个调用数据库表的类,在BLL层应用此类时,如果每次都new创建的话需要频繁的创建和回收,而DAL层这个类里又没有和对象相关的值变量,所以不需要每次都new一个,这时候就可以用单例模式来创建这个DAL实例。

静态方法与单例模式的区别以及为什么要用单例模式而不是静态方法相关推荐

  1. java 静态方法与实例方法的区别_静态方法与实例方法的区分

    Java系列之:看似简单的问题 静态方法和实例化方法的区别 Java程序启动class文件被读取时类被加载,如果有static方法,此时会分配内存,非static方法实例化类时才在内存中分配控件存储, ...

  2. java 内存 静态_Java内存的 静态方法和实例方法的区别及使用场景

    注意:变量指基本数据类型非对象,局部变量不能被静态修饰 1.(静态)成员变量存放在data segment区(数据区),字符串常量也存放在该区 2.非静态变量,new出来的对象存放在堆内存,所有局部变 ...

  3. Java内存的一点理解, 静态方法和实例方法的区别及使用场景

    注意:变量指基本数据类型非对象,局部变量不能被静态修饰 1.(静态)成员变量存放在data segment区(数据区),字符串常量也存放在该区 2.非静态变量,new出来的对象存放在堆内存,所有局部变 ...

  4. 深入浅出剖析静态方法和实例方法的区别

    这是一个经常被时时提出来的问题,很多时候我们以为理解了.懂了,但深究一下,我们却发现并不懂. 方法是我们每天都在写得,很多程序员大多都使用实例化方法,而很少使用静态方法,问原因也说不出来所以然,或者简 ...

  5. 转:静态方法是实例方法的区别

    这是一个经常被时时提出来的问题,很多时候我们以为理解了.懂了,但深究一下,我们却发现并不懂. 方法是我们每天都在写得,很多程序员大多都使用实例化方法,而很少使用静态方法,问原因也说不出来所以然,或者简 ...

  6. python 类变量、实例变量、参数、实例方法、类方法、静态方法 的用法和区别

    #!/usr/bin/env python # -*- encoding: utf-8 -*- """ @Introduce : 类变量.实例变量.参数.实例方法.类方法 ...

  7. java 静态方法和实例方法的区别

    静态方法和实例方法的区别主要体现在两个方面: 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式.而实例方法只有后面这种方 ...

  8. java 静态方法 实例方法的区别_java 静态方法和实例方法的区别

    静态方法和实例方法的区别主要体现在两个方面: 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式.而实例方法只有后面这种方 ...

  9. python静态方法和类方法的区别_python中类的静态方法和类的类方法

    知识回顾: 上一节中,我们深化学习了类的属性监控,主要使用了三个魔法方法:__getattr__ __setattr__ __delattr__ 与此同时在书写属性设置监控的时候,千万不要忘记写__d ...

最新文章

  1. SAP RETAIL 我的第一个寄售类型的跨公司采购订单
  2. 牛客国庆集训派对Day2 F、平衡二叉树 【构造+记忆化搜索】
  3. python单例模式的五种实现方式
  4. OpenGL Multiple Scissors多个剪刀的实例
  5. html文件语言表示网页标题,HTML网页基本结构(HTML文件、编程语言)——十一号笔记...
  6. [NOTE]常用Linux命令总结[Thx for commandlinefu]
  7. 3-6:常见任务和主要工具之正则表达式
  8. C# 二进制替换第一弹 byte 数组替换
  9. 为什么有时不能正确定位到异常的发生位置?
  10. 校园网络项目PT模拟
  11. python 求当前小时前n个小时
  12. (CVPR_2021) Center-based 3D Object Detection and Tracking
  13. 基于Pytorch实现GAT(图注意力网络)
  14. NLP数据增强;中文数据增强包;一键中文数据增强
  15. 数据结构c语言进制转换八进制,C语言数据结构中数制转换实例代码
  16. 如何搭建Bugzilla
  17. 磁盘空间linux命令fdisk,解决fdisk与df命令显示的磁盘空间不一样
  18. Redis(9)——史上最强【集群】入门实践教程
  19. 刘汝佳 例题7-1 除法(暴力解法)
  20. 一刻相册“AI头像生成器”,普通照片秒变超现实大片

热门文章

  1. YOLOv4重磅发布,五大改进,二十多项技巧实验,堪称最强目标检测万花筒
  2. 40题刷爆Keras,人生苦短我选Keras
  3. 推荐一些能提高生产力的 Python 库
  4. 推荐:用动画的形式呈现解LeetCode题目的思路(github上25000多star)
  5. 坚持学习打卡的人,将来会变成什么样?
  6. 最强的Attention函数诞生啦,带给你意想不到的巨大提升!
  7. 当互联网公司聚餐时,他们是如何谈(ge)笑(huai)风(gui)生(tai)的
  8. 项望烽:移动 IM 开发之心跳​
  9. git作死之天坑记录
  10. Microsoft Power BI 学习笔记