effective java读后感1(1-5点)


转http://www.blogjava.net/stone2083/archive/2008/02/19/180550.html
effective java中提供了57条建议。针对这些建议,我谈谈自己的理解。

1.考虑用静态工厂方法代替构造函数
静态工厂方式相比于构造函数的两个优点:
1)可以有符合自己身份的方法名,方便客户端代码的阅读
2)调用的时候,不要求创建一个新的实例。可以返回缓存实例,或者singleton实例等

静态工厂方法的最大缺点:
如果类中没有public或者protected的构造函数,使用静态工厂方法的方式得到实例,那么这个类就无法被继承。
比如
public   class  Demo {
    
private   static  Demo demo  =   new  Demo();

    
public   static  Demo getInstance() {
        
return  demo;
    }

    
private  Demo() {
    }
}
那么这个类就无法被继承。
(当然,鼓励使用组合,而不是继承)

在spring没有流行起来的那些日子里,我大量使用工厂方法,但是使用spring等ioc容器后,这一切都是交给容器去处理了。或许,在客户端代码中,工厂模式会因为这些ioc的出>现,而遭受淘汰。


2.使用私有构造函数强化singleton属性

一旦存在public或者protected的构造函数,那么无法保证一个类,一定是sinleton的。因为无法得知客户端代码是使用构造函数,还是同构静态方法去得到类实例。所以对于一个严格要求singleton的类,那么其构造函数必须是私有的。
既然说到singleton了,那么顺便说下几个常见的创建方法
1)
/**
 * 优点:简单,而且可以确保一定是singletion实例
 * 缺点:类加载时,就会初始化实例,不能做到延迟初始化。
 
*/
public   class  Demo {
    
private   static final Demo demo  =   new  Demo();

    
public   static  Demo getInstance() {
        
return  demo;
    }

    
private  Demo() {
    }
}
2)
/**
 * 优点:lazy load(延迟初始化实例),提高效率
 * 缺点:多线程情况下,可能初始化多份实例
 
*/
public   class  Demo {
    
private   static  Demo demo  =   null ;

    
public   static  Demo getInstance() {
        
if (demo   ==   null  ) {
            demo 
=   new  Demo();
        }
        
return  demo;
    }

    
private  Demo() {
    }
}
3)
/**
 * 优点:lazy load(延迟初始化实例),提高效率
 *              采用double check并且同步的方式,理论上确保在多线程的应用场景中,也只创建一份实例
 * 备注:(涉及到jvm的实现,在实际应用中,也可能生成多份实例,但是几率是相当地低)
 
*/
public   class  Demo {
    
private   static  Demo demo  =   null ;

    
public   static  Demo getInstance() {
        
if (demo   ==   null  ) {
            
synchronized (Demo. class )  {
                
if (demo  ==   null ) {
                    demo 
=   new  Demo();
                }
            }
        }
        
return  demo;
    }

    
private  Demo() {
    }
}


3.使用私有构造函数强化不可实例化能力
咋一看这个标题,觉得不可思议,居然让类不具备实例化能力。但是确实也有一些应用场景,比如一些util类,就不需要实 例化。但是有很大的副作用,就是类无法被继承。所以换成我,就算是util类,我还是会保留其public的构造函数的。客户端就算要实例化这些 util,也无伤大雅。


4.避免创建重复对象
一般情况下,请重复使用同一个对象,而不是每次需要的时候创建一个功能上等价的新对象。这主要是为了性能上的考虑,何况在一般的应用场景下,确实没有必要去重复创建对象。当然有时候为了OO设计考虑,也不特别排斥创建重复的小对象。
需要明确的是,避免创建重复的对象,请不要产生一个误区就是:创建对象的成本非常昂贵。事实上,创建小对象的开销是非常小的,而且现在的jdk gc对于小对象的GC代价也是非常廉价(在之后的日子里,我会针对sun jdk gc,做一次介绍)。比如在做Swing开发的时候,会创建很多EventListener对象,比如在Spring Framework中,就创建很多匿名内隐类对象实现类似ruby等动态语言的Closure(闭包)。
但是也不可否认的是,创建大对象,对大对象的GC 的开销是比较大的。比如初始化一个对象的时候,需要加载10m的文件内容到内存;创建数据库连接对象等等,在这些场景下,创建的开销是相当昂贵了,一定要尽可能避免重复对象的创建(除非特殊需求)。
对于这些大对象,一般采用singleton模式,cache,或者object pool等方式,避免重复的创建。至于采用具体什么方式,需要根据具体的应用场景来决定了。


5.消除过期对象的引用
为什么要这么做?其实只要理解“java内存泄露”这个概念就可以了。java中的内存泄漏不同于C++中的内存泄漏。 C++是需要程序员手工管理内存的语言,创建一个对象,用完之后,需要手工删除这个对象。而java不一样,jdk gc替程序员做了这件事情,一旦对象失去了引用之后,jdk gc就会自动回收这个对象。
为了避免java中的内存泄漏,只需要知道一点就可以:对于无用的对象,必须消除对这个对象的引用。
怎么消除对象的引用呢?难道需要手工设置“object=null;”,那么一旦程序中到处充斥着这样的代码,将会是一件非常恶心的事情,严重影响程序的阅读性。
正确的做法是,每个定义的变量给予最紧凑的作用域,一旦对象结束生命周期,自然就消除了对其的引用。
当然在必要的场合,也不反对采用清空对象引用的方法,但是不推荐。
内存泄漏的症状不能在短时间内反应出来,往往是在程序运行一段时间,一天,一周,一个月,甚至一年,才逐渐显现的,一个经验丰富的程序员,也不能确保其代 码一定不存在内存泄漏的问题。检查内存泄漏问题,往往需要借助工具,heap profile,比如jprofile等等。在linux下面,可以使用jps jstat jinfo jmap等命令去观察。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值