三、接口优于抽象类

java提供两种机制,可以用来定义一个允许多个实现的类型:接口和抽象类。由于java只允许单继承,所以,抽象类作为类型定义受到了极大的限制。

已有的类可以很容易被更新,以实现新的接口。你所需要做的是:增加要求的方法,如果这些方法原先还不存在的话;然后在类的声明上增加一个implements子句。

接口是定义mixin(混合类型)的理想选择。一个mixin是指这样的类型:一个类除了实现它的”基本类型(primary type)"之外,还可以实现这个mixin类型,以表明它提供了某些可供选择的行为。

例如,Comparable是一个mixin接口,它允许一个类表明它的实例可以与其他的可相互比较的对象进行排序操作,这样的接口之所以被称为mixin,是因为它允许可选的功能可被混合到一个类型的基本功能中。抽象类不能被用于定义mixin,同理因为单继承原因。

接口使得我们可以构造出非层次结构的类型框架。类型层次对于组织某些事物是非常合适的,但是其他有些事物并不能被整齐地组织成一个严格的层次结构。

例如,singer(歌唱家),另一个接口代表一个songwriter(作曲家):

public interface Singer{AudioClip Sing(Song s);
}public interface Songwriter{Song compose(boolean hit);
}

接口使得安全性地增强一个类的功能成为可能,做法通过介绍的包装类(WrapperClass)模式。如果你用抽象类来定义类型,那么这样就使得程序员除了使用继承的手段来增加功能之外,没有别的选择途径。这样得到的类与包装类相比,功能更差,也更加脆弱。

可以把接口和抽象类的优点结合起来,对于你期望导出的每一个重要接口,都提供一个抽象的骨架实现(skeletal implementation)类。在这里接口的作用任然是定义类型,但是骨架实现类负责所有与接口实现相关的工作。骨架实现被称为AbstractInterface,这里的interface是所实现的接口的名字。

例如,Collections Framework为每个重要集合接口都提供了一个骨架实现,包括AbstractCollection为Collection接口、AbstractSet(为set接口)、AbstractList(为list接口)和AbstractMap(为Map接口).

如果设计合理的话,利用骨架实现,程序员可以很容易的提供他们自己的接口实现。例如,下面是一个静态工厂方法,它包含一个完整的、功能全面的List实现:

//List adapter for int array
static List intArrayAsList(final int[] a){if(a==null)throw new NullPointerException();return new AbstractList(){public Object get(int i){return new Integer(a[i]);            }public int size(){return a.length;}public Object set(int i,Object o){int oldVal = a[i];a[i] = ((Integer)o).intValue();return new Integer(oldVal);}}
}

这个例子是一个Adapter,它使得一个int数组可以被看做一个Integer实例列表。由于int值和Integer实例之间来回转换开销,它的性能不会非常好。注意,这个例子只提供了一个静态工厂,并且这个类是一个可被访问的匿名类(anonymous class),它被隐藏在静态工厂的内部。

骨架实现的优美之处在于,它们为抽象类提供了实现上的帮助,但又没有强加“抽象类被用作类型定义时候”所特有的严格限制。对于一个接口的大多数实现来讲,扩展骨架实现是一个很显然的选择,但也确实只是一个选择而已。如果一个预先已经定义好的类无法扩展骨架实现类,那么,这个类总是可以手工实现这个接口。尽管如此,骨架实现类仍然能够有助于接口的实现。实现了这个接口的类可以把对于接口的方法的调用,转发到一个内部私有的实例上,而这个内部私有类扩展了骨架实现类。这项技术被称为模拟多重继承(simulated multiple inheritance),这项技术具有多重继承的绝大多数优点,并且避免了相应的缺陷。

嵌套类--优先考虑静态成员类

嵌套类(nested class)是指被定义在另一个类的内部的类,嵌套类存在的目的应该只是为它的外围类提供服务。如果一个嵌套类将来可能会用于其他的某个环境中,那么它应该是顶层类(top-level class).

嵌套类有四种:

  • 静态成员类(static member class);
  • 非静态成员类(nonstatic member class);
  • 匿名类(anonymous class);
  • 局部类(local class);

Member Types(成员类型)即作为外部类的一个成员存在,与外部类的属性、方法并列同级的类型。成员内部类中不能定义静态变量,但可以访问外部类的所有成员.

除了第一种,其他三种都被称为内部类(inner class),那什么时候使用哪种嵌套类呢?为什么这样做呢?

静态成员类是一种最简单的嵌套类。最好把它看做是一个普通的类,只是碰巧被声明在另一个类的内部而已。它可以访问外围类的所有成员,包括那些声明为私有的成员。静态成员类是外围类的一个静态成员,与其他的静态成员一样,也遵守同样的可访问性规则。如果它被声明为私有的,那么它只能在外围类的内部才可以被访问等等。

静态成员类的一个通常用法是作为公有的辅助类,仅与它的外部类一起使用时才有意义。

非静态内部类nested inner class:

内部类隐含有一个外部类的指针this,因此,它可以访问外部类的一切资源(当然包括private)
外部类访问内部类的成员,先要取得内部类的对象,并且取决于内部类成员的封装等级。
非静态内部类不能包含任何static成员.

匿名类的适用性有一些限制。

  1. 因为它们同时被声明和实例化,所以匿名类只能被用在代码中它将被实例化的那个点上。
  2. 因为匿名类没有名字,所以在它们被实例化之后,就不能够再对它们进行引用,如果不是这种情况就不能使用匿名类。
  3. 因为匿名类出现在表达式的中间,所以它们应该非常简短,可能是20行或者更少,太长的匿名类会影响程序的可读性。

匿名类常用用法:

A、匿名类的一个通常用法是创建一个函数对象(function object),比如Comparator实例。排序:

//Typical use of an anonymous class
Arrays.sort(args,new Comparator(){public int compare(Object o1,Object o2){return ((String)o1.length()-((String)o2).length();}
});

B、匿名类的另一个常用的用法是创建一个过程对象(process object),比如Thread、Runnable或者TimerTask实例。

C、还有一个用法是在一个静态工厂方法的内部(参考IntArrayAsList方法)。

D、在复杂的类型安全枚举类型(它要求为每个实例提供单独的子类)中,用于公有的静态final域的初始化器中。

局部类是四种嵌套类中最少使用的类。在任何“可以声明局部变量”的地方,都可以声明局部类,并且局部类也遵守同样的作用域规则。即在方法中定义的内部类,与局部变量类似,在局部内部类前不加修饰符public或private,其范围为定义它的代码块。
注意:局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的。

public class Outer {private int s = 100;private int out_i = 1;public void f(final int k){final int s = 200;int i = 1;final int j = 10;class Inner{ //定义在方法内部int s = 300;//可以定义与外部类同名的变量//static int m = 20;//不可以定义静态变量Inner(int k){inner_f(k);}int inner_i = 100;void inner_f(int k){System.out.println(out_i);//如果内部类没有与外部类同名的变量,在内部类中可以直接访问外部类的实例变量System.out.println(k);//*****可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的*****//System.out.println(i);System.out.println(s);//如果内部类中有与外部类同名的变量,直接用变量名访问的是内部类的变量System.out.println(this.s);//用"this.变量名" 访问的也是内部类变量System.out.println(Outer.this.s);//用外部"外部类类名.this.变量名" 访问的是外部类变量
         }}new Inner(k);}public static void main(String[] args) {//访问局部内部类必须先有外部类对象Outer out = new Outer();out.f(3);}
}

简而言之,共有四种不同的嵌套类,每一种都有自己的用途。

Effective java笔记3--类和接口2相关推荐

  1. JAVA笔记:shape类(接口,继承,lambda表达式...)

    目录 写一段程序,实现shape面积,并可以对面积大小排序 定义父类shape类,并定义方法Area() 定义第一个子类Circle类 定义第二个子类Rect类 定义接口Comparator,并写入c ...

  2. Effective Java笔记第五章枚举和注解第三节用EnumSet代替位域

    Effective Java笔记第五章枚举和注解 第三节用EnumSet代替位域 在以前如果一个枚举类型的元素主要用在集合中,一般就会使用int枚举模式.比如说: public class Demo ...

  3. java笔记之抽象类和接口

    前言 java笔记之抽象类和接口是开发人员的设计工具 正文 1.抽象类 客观存在的一类事物,当这类事物都是抽象的,无法具体的描述. 1)语法: 修饰符 abstract class 类名{ } 2)特 ...

  4. Java笔记:抽象类和接口

    Java笔记:抽象类和接口 抽象类 接口 接口多重实现 接口继承接口 嵌套接口 工厂模式 抽象类 在普通类中,一个类必须实现自身写的所有方法,每个方法必须含有自己的方法体.即便先创建一个父类,再由后续 ...

  5. 【java笔记】常用函数式接口(4):Funtion接口

    ​​​​​​​​​​​​​​[java笔记]常用函数式接口(1):Supplier接口_m0_52043808的博客-CSDN博客 [java笔记]常用接口(2):Consumer接口_m0_5204 ...

  6. 【java笔记】常用函数式接口(1):Supplier接口

    [java笔记]常用接口(2):Consumer接口_m0_52043808的博客-CSDN博客 [java笔记]常用函数式接口(3):Predicate接口_m0_52043808的博客-CSDN博 ...

  7. Effective Java 第三版读书笔记(类和接口)

    第15条.使类和成员的可访问性最小化 对于成员有四种可访问级别: 1.私有的(private)----- 只有在声明该成员的顶层类内部才可以访问这个成员. 2.包级私有的(package-privat ...

  8. Effective java笔记3--类和接口1

    一.使类和成员的可访问能力最小化 要想区别一个设计良好的模块与一个设计不好的模块,最重要的因素是,这个模块对于外部的其他模块而言,是否隐藏了内部的数据和其他的实现细节.一个设计良好的模块会隐藏所有的实 ...

  9. 几个重要的java数据库访问类和接口

    编写访问数据库的Java程序还需要几个重要的类和接口. DriverManager类 DriverManager类处理驱动程序的加载和建立新数据库连接.DriverManager是java.sql包中 ...

  10. java接口版本控制_为什么要在Java中控制类和接口的可见性

    java接口版本控制 维护是软件开发的重要方面之一,并且经验证明,保持较低组件可视性的软件比暴露更多组件的软件更易于维护. 您不会在一开始就意识到它,但是在重新设计应用程序时会严重错过它. 由于保持向 ...

最新文章

  1. 构建知识图谱,让自己更值钱
  2. Java使用javax.mail.jar发送邮件并同意发送附件
  3. java web购物车代码_java web开发之购物车功能实现示例代码
  4. COM_PRODUCT_READ_SINGLE called by composite API when line item is deleted
  5. Vue.js 还是 React?你会选择哪一个?为什么?
  6. RN开发模型,供参考
  7. 函数的极值点、零点、驻点、拐点的理解
  8. 211. 字符串置换
  9. linux远程取证,linux系统取证
  10. 电信系统服务器地址,电信高速dns服务器地址谁知道?
  11. WebStorm快捷键及配置
  12. 深入浅出谈开窗函数(一)
  13. ES6+(前端面试题整合)
  14. Vue3+Vite+TS+Eslint搭建生产项目
  15. Oracle dataset 工具,[Oracle] 32-bit ODAC 與 Visual Studio工具 (.NET)
  16. Excel当中LookUp与VLookUp函数详解
  17. 英语单词笔记(沪江-新概念英语第三册篇)
  18. 前世的五百次回眸才能换得今生的一次擦肩而过
  19. CubeMX系列教程——9 定时器中断
  20. 监视器的功能,光源分类,TFSF光源斜入射的实例(有/无边界)

热门文章

  1. IBM Cloud Speech to Text 语音识别
  2. Python编译出现错误SyntaxError: Non-ASCII character '\xe7' 时解决方法
  3. 五大场景深解无服务器架构如何实践?
  4. 企业级Nginx服务基础到架构优化详解--25条
  5. 移动数据分析服务使用教程
  6. 构建之法现代软件工程(第五次)
  7. ftp connect: No route to host 解决过程
  8. Runtime应用(三)实现NSCoding的自动归档和自动解档
  9. 运维自动化之zabbix (Discovery)(9)
  10. .NET简谈组件程序设计之(详解NetRemoting结构)