Java程序设计语言提供两种机制,可以用来定义允许多个实现的类型:接口和抽象方法,这两者直接醉为明显的区别在于,抽象类允许某些方法的实现,但接口不允许,一个更为重要的区别在于,为了实现由抽象类定义的类型,类必须成为抽象类的一个子类。任何一个类,只要定义了所有必要的方法,并且遵守通用约定,它就被允许实现一个借口,而不管这个类是处于类层次的哪个位置。因为Java只允许单继承,所有抽象类作为类型定义受到类极大的限制。

  现有的类很容易被更新,以实现新的接口。

  如果你希望让两个类扩展同一个抽象类,就必须把抽象类放到类型层次结构的高处,以便这两个类的一个祖先成为它的子类。遗憾的是这样做会间接到伤害到类层次,迫使这个公共祖先到所有后代类都扩展这个新的抽象类,无论它对于这些后代类是否合适。

  接口是定义混合类型的理想选择。

  接口允许我们构造非层次结构的类型框架。

  假如我们有两个接口,一个表示歌唱家,另一个表示作曲家,在现实生活中,有很多人即是歌唱家又是作曲家,如果是接口,我只需要同时实现这两个接口就可以,如果是抽象类,因为Java是单继承的,我就没有办法描述这一类的人。

  虽然接口不允许包含方法的实现,但是,使用接口来定义类型并不妨碍你为程序猿提供实现上的帮助。通过对你导出的每个重要接口都提供一个抽象骨架的实现类,把接口和抽象类的优点都结合起来。接口的作用仍然是定义类型,但是骨架的实现类接管类所有与接口实现相关的工作。

  骨架为接口提供实现上的帮助,但又不强加“抽象类被用作类型定义时”所特有的严格限制。对于接口大多数的实现来讲,扩展骨架实现类是个很显然的选择,但不是必须的。如果预制的类无法扩展骨架实现类,这个类始终可以收工实现这个接口。此外,骨架实现类仍然有助于接口的实现。实现类这个接口的类可以把对于这个接口方法的调用,转发到一个内部私有类的实例上,这个内部私有类扩展骨架实现类。这种方法被称作模拟多重继承。这项技术具有多重继承的绝大多数有点,同时又避免了相应的缺陷。

  编写骨架实现类相对比较简单,只是有点单调乏味。首先,必须认真研究接口,并确定哪些方法时最为基本的,其他方法则可以根据它们来实现。这些方法将成为骨架实现类中的抽象方法。然后,必须为接口中的所有其他的方法提供具体实现。例如,下面是Map.Entry接口的骨架实现类:

/**
* 接口优于抽象类
* @author weishiyao
*
* @param <K>
* @param <V>
*/
// Skeletal Implementation
public abstract class AbstractMapEntry<K, V> implements Map.Entry<K, V>{ // Primitive operations
public abstract K getKey();
public abstract V getValue(); // Entries in modifiable maps must override this method
public V setValue(V value) {
throw new UnsupportedOperationException();
} // Implements the general contract of Map.Entry.equals
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Map.Entry)) {
return false;
}
Map.Entry<?, ?> arg = (Map.Entry) obj;
return equals(getKey(), arg.getKey()) && equals(getValue(), arg.getValue());
} private static boolean equals(Object obj1, Object obj2) {
return obj1 == null ? obj2 == null : obj1.equals(obj2);
} // Implements the general contract of Map.Entry.hashCode
@Override
public int hashCode() {
return hashCode(getKey()) ^ hashCode(getValue());
} private static int hashCode(Object obj) {
return obj == null ? 0 : obj.hashCode();
}
}

  骨架实现类时为了继承的目的而设计的,这种使用方式在平时开发中经常可以见到,很多框架中都有使用方式,之前为也是见过好多次框架中这么使用,大致能明白这么写是干什么,这次经过这么详细讲解,算是彻底明白为什么要这么使用了,能想到这种写法的人真的也是大神了。

  

  

EffectiveJava——接口优于抽象类的更多相关文章

  1. Effective Java 第三版—— 20. 接口优于抽象类

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  2. 从接口、抽象类到工厂模式再到JVM来总结一些问题

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 涉及到的知识点总结如下: 为什么使用接口? 接口和抽象类的区别 简单工厂模式总结 Java中new和newInstance的区别 J ...

  3. (转)深入理解Java的接口和抽象类

    原文地址: http://www.cnblogs.com/dolphin0520/p/3811437.html 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP ...

  4. c++ 接口和抽象类

    其实对抽象类与接口的区别一直是搞不太清楚,最近正在学习<设计模式>,期间用到了很多c++多态的知识.这是才恍然发现,是应该整理下这方面的知识了.但在翻阅书本.上网查阅资料之际,发现有篇文章 ...

  5. android中接口和抽象类的区别

    最近发现很多基础有点生疏了,特地写一点博客来巩固一下.今天主要来谈谈接口和抽象类的区别,我们在项目的很多地方都会用到接口或者抽象类,但是它们之间的一些区别和相同点不知道大家有没有注意到,还有就是,什么 ...

  6. 深入理解Java的接口和抽象类(转)

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

  7. c#接口与抽象类的区别

    abstract 修饰符用于表示所修饰的类是不完整的,并且它只能用作基类.抽象类与非抽象类在以下方面是不同的: 抽象类不能直接实例化,并且对抽象类使用 new 运算符是编译时错误.虽然一些变量和值在编 ...

  8. Java接口和抽象类的区别

    今天看到项目中,写了一个抽象类,里面有很多方法继承了这类,当调用这个接口时,采用的是这个抽象类去调方法的,当时一想,这个不就是我们说的Java的多态的特征: 继承:存在继承关系的子类和父类 重写:子类 ...

  9. 深入理解Java的接口和抽象类

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

随机推荐

  1. 在Win8.1系统下如何安装运行SQL Server 2005 (以及安装SQL Server 2005 Express打补丁)

    在Win8.1系统下SQL Server 2005 安装失败怎么办? 需要替换两个文件及打sqlserver sp4补丁. 以下是操作过程. 按正常情况,在Win8/Win8.1系统下安装微软的SQL ...

  2. 初识WEB:输入URL之后的故事【转】

    转载一篇文章,分析的是浏览器输入url后所执行的一系列操作!写得非常清晰易懂,分享给大家! 作者:Jesse 出处:http://jesse2013.cnblogs.com/ 本文版权归作者和博客园共 ...

  3. struts1的ActionForm的作用域(生命周期)

    转自:http://biancheng.dnbcw.info/java/240347.html 今天查找一个问题:我在列表页面添加一个查询条件,然后查询符合条件的数据.查询结果正确.然后我进入其它菜单 ...

  4. jquery-migrate.js

    这个插件可以用来检测和恢复在jQuery1.9版本中已删除或已过时的API.

  5. “远程调试监视器(MSVSMON.EXE)似乎没有在远程计算机上运行“的完美解决方案

    今天调试程序时,Visual Studio突然报出了如下错误: Microsoft Visual Studio 远程调试监视器(MSVSMON.EXE)似乎没有在远程计算机上运行.这可能是因为防火墙阻 ...

  6. 使用ssh免密码登录其他机器

    本机 ssh-keygen -t rsa – cd ~/ssh – cp -p id_rsa.pub authorized_keys2 – chmod go-rwx authorized_keys2 ...

  7. ADO.NET 3.5高级编程:应用LINQ&Entity Framework

    http://item.jd.com/10080604.html 第1部分 ADO.NET3.5概览第1章 使用ADO.NET3.5提供的新方法访问数据1.1 语言集成查询LINO1.1.1 LIQ  ...

  8. php 将一个二维数组转换成有父子关系的数组

    <?php /** * Tree 树型类(无限分类) * * @author Kvoid * @copyright http://kvoid.com * @version 1.0 * @acce ...

  9. JavaScript Scoping and Hoisting

    JavaScript中所有变量及函数名会自动提升 http://www.cnblogs.com/betarabbit/archive/2012/01/28/2330446.html

  10. (转)linux文件读写的流程

    转自http://hi.baidu.com/_kouu/item/4e9db87580328244ef1e53d0 在<linux内核虚拟文件系统浅析>这篇文章中,我们看到文件是如何被打开 ...