我们编程中最常用的模式是singleton模式,但是singleton模式用在哪里呢?为什么使用单例模式而不是静态方法?要理解这些问题,需要从静态方法和非静态方法的区别和联系入手 。
I .静态方法内存驻留 。非静态方法只有在使用时才分配内存?
一般认为是这样,因为怕静态方法占用内存太多,建议使用非静态方法 。其实这种理解是错误的 。
为什么会这样?让我们从内存分配开始:
托管堆的定义:对于32位应用,应用完成进程初始化后,CLR会在进程的可用地址中分配一个保留地址空 。它是进程的可用地址空之间的内存区域(每个进程可以使用4GB),但不对应任何物理内存 。这个地址
托管堆分为几个区域,其中最重要的是垃圾收集堆(GC Heap)和加载器堆 。GC堆用于存储对象实例,由GC管理 。加载器堆分为高频堆、低频堆和存根堆,不同的堆存储不同的信息 。加载器堆最重要的信息是元数据相关的信息,也就是类型对象 。每种类型都表示为加载器堆上的一个方法表,存储的元数据信息(如基类型、静态字段、实现的接口、所有方法等)都记录在方法表中 。加载器堆不受GC控制,其生命周期是从创建到AppDomain卸载 。(摘自《你必须知道 。净”)
由此可以看出,静态方法和非静态方法实际上都是放在内存中的方法表中的 。当一个类第一次加载时,它会将静态方法和非静态方法都写入加载器堆中的方法表,而加载器堆不受GC控制,所以一旦加载,在AppDomain卸载之前,GC不会回收它 。
由此可以看出,静态方法和非静态方法都是在第一次加载后内存常驻,所以方法本身在内存中没有区别,所以不存在“静态方法内存常驻,非静态方法只在使用时分配内存”的结论 。
二、静态和非静态方法的区别?
内存上的区别在于,当非静态方法创建实例对象时,由于每个对象的属性的值是不同的,所以在创建新的实例时,会在GC Heap中做一个实例属性的副本,新创建的对象会放在堆栈上,堆栈指针会指向刚刚复制的实例的内存地址 。但是,静态方法是不必要的,因为静态方法中的静态字段存储在方法表中,只有一个副本 。
所以静态方法和非静态方法,在调用速度上,静态方法会更快,因为非静态方法需要实例化和内存分配,而静态方法不用,但是速度上的差异可以忽略 。
三 。为什么要有非静态的方法?
在早期的结构化程序设计中,几乎所有的方法都是“静态方法”,实例化方法概念的引入是在面向对象概念出现之后 。静态方法和实例化方法的区别不能单从性能上理解 。创造了C、Java、C #等面向对象语言的大师们引入实例化方法并不是为了解决什么性能和内存问题,而是为了让开发更加模块化和面向对象 。这样,静态方法和实例化方法的区别就是解决模式的问题 。
接下来,我们继续思考 。如果我们都用静态方法而不是非静态方法,难道不能实现同样的功能吗?是的,没错,但是你的代码是基于对象的,不是面向对象的,因为面向对象的继承和多态都是非静态方法 。
第二个原因是为什么我们不推荐所有的静态方法 。如果我们是多线程,如果一个静态方法中使用了一个静态字段,这个静态字段可以被多线程修改 。因此,如果在静态方法中使用静态变量,就会出现线程安全问题 。当然,即使不是多线程,因为只有一个静态字段,还是会有被其他地方修改的问题 。
从这三点出发,我们得出以下结论:
一、什么时候用静态方法,什么时候用非静态方法?
既然静态方法和实例化的区别是为了解决模式的问题,那么如果考虑到不需要继承和多态,就可以使用静态方法 。但是,在不考虑继承和多态的情况下使用静态方法并不是一个好的编程思路 。
另一方面,如果一个方法与其类的实例对象无关,那么它应该是静态的,否则它应该是非静态的 。所以和工具一样,一般都是静态的 。
第二,为什么要用singleton模式而不是静态方法?
从面部物体的角度来看:
虽然都可以达到目的,但是一个是基于对象的,一个是面向对象的 。正如我们可以不用面对对象就能解决问题一样,面向对象的代码提供了更好的编程思想 。
如果一个方法与其类的实例对象无关,那么它应该是静态的,否则它应该是非静态的 。如果我们真的应该使用非静态方法,但在创建类时只需要维护一个实例,我们就需要使用singleton模式 。
例如,当系统运行时,我们需要加载一些配置和属性 。这些配置和属性必须存在并且是公共的 。同时,它们需要在整个生命周期内存在,所以只需要一个副本 。这时候如果我再需要的时候需要一个新的,然后再给他赋值,显然是浪费内存,再赋值也没有意义 。所以这个时候我们需要singleton模式或者静态方法来维护一个且只有一个副本,但是这个时候这些配置和属性都是通过面向对象编码得到的,所以要用singleton模式,或者不是面向对象,但是它本身的属性应该是面向对象的 。虽然我们可以用静态方法解决问题,但最好的解决方案应该是singleton模式 。
从功能上讲,singleton模式可以控制单例的数量;可以进行有意义的推导;对实例的创建有更自由的控制;
三 。其他:
数据库连接可以是单例的吗?
如果只是简单的在SingleTon对象中封装一个connection对象,那是错误的,所以连接池中有多个链接可用 。如果使用singleton,访问WEB时只能使用一个数据库链接 。那不是死得很惨吗?
【为什么要有单例设计模式 为什么要用单例模式】然而,单例模式可以用在连接池中 。例如,在初始化期间创建100个连接对象,然后在需要时提供一个 。用后放回水池 。我们使用单例模式来确保只有一个连接池 。
再比如,调用数据库表的类是用DAL层写的 。当这个类应用于BLL层时,如果每次都是新创建的,就需要频繁的创建和回收 。但是DAL层中没有与这个类中的对象相关的值变量,所以没有必要每次都创建一个新的 。此时,您可以使用singleton模式来创建这个DAL实例 。
- 红酒倒进杯子为什么会有泡沫
- 北宋时期与其交战的交趾国是不是越南,为什么不是越国
- 为什么枸杞吃完舌头是红色的
- 饮食上如何控制扁平疣生长 扁平疣为什么越长越多
- 为什么车厘子苦
- 文莱这么小为什么没人攻打 文莱是哪个国家
- 鱼池养不活鱼 海鲜池鱼为什么养不活
- 两癌筛查前后注意事项 两癌筛查为什么3年一次
- 钢价为什么会涨 银价会涨吗
- 手足口病为什么会发烧 手足口病是什么疾病
