Java static关键字的重新思考
上完java课,虽然也写了不少的java代码,但是一直有不少的疑惑,而static关键字一直困惑着我很久,今天无意探究竟,上知乎再仔细查了一下,发现了这个话题的优秀答案
这篇文章彻底把我之前对static的理解概念土崩瓦解,看来我还是低估了设计语言大师的智慧,老以为非静态声明函数会造成实例化多个实例时会造成内存空间的浪费,实际上每个实例里面的函数方法在实例的内存区域中仅仅只有个引用而已,并且此引用指向了该函数方法的内存头地址。看完文章后再想想之前我写的代码,整个人都有点傻逼了,写出的所谓优化,反而是不符合面向对象编程的规范。
但是后来我又思考了一下,在面向对象编程已经流行了20多年的今天,为何static关键字还有存在的意义呢?在一顿饭时间的思考之后,我发现静态函数在对象的功能扩展上有着很强大的功能,使用恰当的话,确实可以优化内存的占用。
比方说,拿个游戏举个例子,假设我们对士兵的基本装备有定性的要求(在类中定义各种非静态属性),因此训练出来的士兵,都有各自的基本装备(对象的属性与方法),但是你总不可能在基本属性里写士兵带at火箭筒,m240重机枪,m320步枪榴弹,便携无线电基站。。。如果真这样,训练出来的士兵要重死了(实例化对象占用内存大),结果在任务中就一个持刀歹徒,拿个手枪突突两下就解决了,那什么火箭筒完全是摆设,有点小题大作了。
于是,在面向对象中有种比较好的解决方法,比如基础类就是防具+人组成的士兵,这时我可以用继承的方式分化成医疗兵带步枪,工程兵带冲锋枪+火箭筒,补给兵机枪+弹药袋,侦察兵狙击枪+望远镜。如此分配兵种,士兵装备也刚刚好不会过重,能充分利用好。但是这些士兵是需要训练的(实例化,new操作,要单独给一片内存空间),要资源的,一个任务需要1个人绝不用2个。这种情况,一个专门为装有静态方法的类就起到拓展的作用。
虽然说静态方法在程序启动的时候就占用了内存了,而且static用多了也不是好习惯,容易导致内存溢出。但是按需求来重外部扩展静态方法,是一个不错的方法。比方说地面的步兵呼叫飞行员进行地面打击(消息传递,一个对象使用另一个的对象的方法,需要实例化的对象),但也可以呼叫总部,用远程导弹进行地面打击(调用公共类中的静态方法,不需要实例化对象,用公共类调用,但静态方法同样要占用内存,且要在程序结束后才能释放)。区别就在于,对于这个军事系统来说,外派的资源前者多了架飞机,如果用不到空中打击,还废油呢。。。
因此对于一些经常使用的公共方法,且这些公共方法可以作为扩展的话,可以已静态方法的形式单独写在一个类中,当其他类需要使用的时候,单独封装一个方法调用公共类的静态方法,以便形成最小的扩展,节约内存资源。
代码例子:
在map类中封装一个方法,实现面向对象编程的规范,此方法调用kruskalmap类中的静态方法kruskalalgo,并把此map实例传入此静态函数。如果不想用kruskal算法了,还可以修改代码,换用prime类的静态方法。注意,静态方法会常驻内存,只有jvm关闭后内存才会释放,因此只扩展经常需要调用的函数。
静态方法的执行效率比非静态更高,因为在堆中是地址是连续,而非静态是离散的,使用的函数才会申请内存。
另一种是针对函数很少使用的情况,该类的函数是非静态的,利用实例,用完就释放方法的内存,相比直接面向对象的写法慢一些,因为涉及到new:
测试用例:
测试结果:
上一篇: 还想当流浪狗?
下一篇: 搭建Nuget服务器(Nuget私服)