为什么
1、静态方法常驻内存,非静态方法只有应用的时候才分配内存?
个别都认为是这样,并且怕静态方法占用过多内存而倡议应用非静态方法,其实这个了解是谬误的。
为什么会这样,先从内存调配开始说起:
托管堆的定义:对于 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 卸载
由此咱们也明确了,静态方法和非静态方法,他们都是在第一次加载后就常驻内存,所以办法自身在内存里,没有什么区别,所以也就不存在”静态方法常驻内存,非静态方法只有应用的时候才分配内存“这个论断了。
2、静态方法和非静态方法的区别?
在内存中的区别是,非静态方法在创立实例对象时,因为属性的值对于每个对象都各不相同,因而在 new 一个实例时,会把这个实例属性在 GC Heap 里拷贝一份,同时这个 new 进去的对象放在堆栈上,堆栈指针指向了方才拷贝的那一份实例的内存地址上。而静态方法则不须要,因为静态方法外面的动态字段,就是保留在 Method Table 里了,只有一份。
因而静态方法和非静态方法,在调用速度上,静态方法速度肯定会快点,因为非静态方法须要实例化,分配内存,但静态方法不必,然而这种速度上差别能够忽略不计。
3、为什么要有非静态方法?
晚期的结构化编程,简直所有的办法都是“静态方法”,引入实例化办法概念是面向对象概念呈现当前的事件了,辨别静态方法和实例化办法不能单单从性能下来了解,创立 c ++,java,c# 这样面向对象语言的巨匠引入实例化办法肯定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化形式的辨别是为了解决模式的问题。
接下来持续思考,如果咱们全副用静态方法,不必非静态方法,不是一样能实现性能吗?是的,没错,然而你的代码是基于对象,而不是面向对象的,因为面向对象的继承和多态,都是非静态方法。
第二个起因是为什么不倡议都用静态方法,咱们如果多线程的状况下,如果静态方法应用了一个动态字段,这个动态字段能够会被多个线程批改,因而说如果在静态方法里应用了动态变量,这就会有线程平安问题,当然了,就算不是多线程,因为动态字段只有一份,同样会有被其余中央批改的问题。
从这三点咱们得出的论断如下:
1、什么时候用静态方法,什么时候应用非静态方法?
既然静态方法和实例化形式的辨别是为了解决模式的问题,如果咱们思考不须要继承和多态的时候,就能够应用静态方法,但就算不思考继承和多态,就一律应用静态方法也不是好的编程思维。
从另一个角度思考,如果一个办法和他所在类的实例对象无关,那么它就应该是动态的,否则就应该是非动态。因而像工具类,个别都是动态的。
2、为什么应用单例模式而不必静态方法?
从面相对象的角度讲:尽管都能实现目标,然而他们一个是基于对象,一个是面向对象的,就像咱们不面相对象也能解决问题一样,面相对象的代码提供一个更好的编程思维。
如果一个办法和他所在类的实例对象无关,那么它就应该是动态的,反之他就应该是非动态的。如果咱们的确应该应用非动态的办法,然而在创立类时又的确只须要保护一份实例时,就须要用单例模式了。
比如说咱们在零碎运行时候,就须要加载一些配置和属性,这些配置和属性是肯定存在了,又是公共的,同时须要在整个生命周期中都存在,所以只须要一份就行,这个时候如果须要我再须要的时候 new 一个,再给他调配值,显然是节约内存并且再赋值没什么意义,所以这个时候咱们就须要单例模式或静态方法去维持一份且仅这一份拷贝,但此时这些配置和属性又是通过面向对象的编码方式失去的,咱们就应该应用单例模式,或者不是面向对象的,但他自身的属性应该是面对对象的,咱们应用静态方法尽管能同样解决问题,然而最好的解决方案也应该是应用单例模式。
从性能上讲:单例模式能够管制单例数量;能够进行有意义的派生;对实例的创立有更自在的管制;
单例模式
在任何时候,该类只能被实例化一次,在任何时候,拜访该类的对象都是同一个,且只有一个。
实现形式
1、应用类私有的动态成员来保留该惟一对象
2、应用私有的动态成员工厂办法
3、应用枚举类的形式来实现单例
单例破损
反射的形式来实例化或序列化都有可能使单例模式生效。