【第15条】要么专门为继承而设计,并给出文档说明,要么禁止继承

探讨了在Java中为继承设计类时遇到的问题,特别是实现Cloneable和Serializable接口带来的挑战。分析了这些问题的根本原因,并提出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    这一条是承接上一条的,所有为继承而设计的类都必须有充足的文档来精确地描述改写每一个方法所带来的影响。也就是要求文档中必须写明那些方法是要求改写的,那些是自用的。对于每一个公有或保护的方法或者构造函数,它的文档必须指明它调用了哪些可改写的方法,是以什么顺序调用的,每个调用结果又是如何影响后续的处理过程的。

 

    这一条中需要特别注意的一段是:在为了继承而设计类的时候,Cloneable和Serializable接口表现出了特殊的困难。如果一个类是为了继承而设计的,那么无论实现其中哪个接口都不是一个好主意,因为它们把一些实质性的负担转嫁到了扩展这个类的程序员的身上。

 

    看到这一段是最让我紧张的,因为我的那些转为继承而设计的类(甚至写成抽象类,可能又触犯了下一条),这两个接口都实现了!仔细研读过【第10条】和【第54条】后,我基本理解了上述结论的原因:

 

     首先是Cloneable接口,【第10条】中已经降到了,再简单回顾一下:java.lang.Object对于clone的约定要求所有子类要首先调用超类的clone方法,然后修改那些需要修改的引用。换句话说就是要递归clone方法。这就是说不能再像equals、hashCode、toString方法那样仅在超类中实现,而子类无需改写了,所有实现了Cloneable接口的类都必须改写clone方法。加之【第10条】中所见到的,改写clone方法的复杂性(N多类型都只是影子克隆),所以这些困难就转移到了子类的实现者身上了。尤其对于团队开发,不能要求每一个开发者都是资深Java程序员呀。

 

     再说说Serializable接口(详细分析稍后见【第54条】):为了保证兼容性,也就是说要保证由之前版本所序列化出来的字节流,能被之后的版本成功地反序列化,反之亦然。这就把你自己的灵活性限定死在私有成员这个很小的范围内了,在新版本中你不能增加新的公有域,也不能改变原公有方法的返回值。如果这个类是为继承而设计的,那么子类的实现者将会面临同样严格的约束,超类和子类的设计者同时被兼容性所禁锢。

 

     在我的案例中,由于这些转为继承而设计的类都是JavaBean,所以Cloneable接口可以放弃了,使用org.apache.commons.beanutils.BeanUtils.cloneBean来替代clone。而Serializable接口是躲不开的,前后台的通讯还要靠它呢。那么怎么办呢?好在我所设计的Framework只是一个开发框架,而不是通用的技术框架,基本不可能有不同的子类在不同的Framework版本下编译的情况,也不可能有不同版本的class文件在两台服务器间通讯的情况。所以,我可以不受此约束所限,升级版本的时候大胆地修改那些公有成员。然而这只是个特例,甚至有的时候可能仅在一个项目内适用,如果你所设计的是一个通用的技术框架,那么请小心。加入JRE的作者不小心违反这一约定,那么可能相同的软件分别在不同版本JRE的服务器上运行,之间通讯时,就“对不上暗号了”。

 

 

 

 

【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值