Java 接口和抽象类


接口

Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

<修饰符>interface<接口名>{
[<常量申明>]
[<抽象方法申明>]
}

接口是类型转换的前提、是动态调用的保证。
实现某一接口就完成了类型的转换(多重继承);
动态调用只关心类型,不关心具体类。
一个方法的特征仅包括方法的名字,参数的数目和种类,方法的返回类型,而不包括参数的名字以及所抛出来的异常;


接口的特点
1、Java接口中只能包含public static final类型的成员变量和public abstract类型的成员方法;
  1.1、Java接口中的成员变量默认都是public static final类型的(都可省略),必须被显示初始化,即接口中的成员变量为常量(大写,单词之间用"_"分隔);
  1.2、Java接口中的方法默认都是public abstract类型的(都可省略),没有方法体;
2、接口中没有构造方法,不能被实例化,但允许定义接口类型的引用变量,该引用变量引用实现了这个接口的类的实例;
3、一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口;
4、Java接口必须通过类来实现它的抽象方法;
  4.1、当类实现了某个Java接口时,它必须实现接口中的所有抽象方法,否则这个类必须声明为抽象类;
  4.2、一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承.
5、接口的可插入性:单继承性,多实现性;


为何用接口:

Java是一种单继承的语言,若要给已有父类的具体类增加新功能,在OCP原则下,解决是给它的父类加父类,或者给它父类的父类加父类,直到移动到类等级结构的最顶端。这样一来,对一个具体类的可插入性的设计,就变成了对整个等级结构中所有类的修改。

当有了接口,以上例子中,就不需要维护整个等级结构中的所有类了.

在一个等级结构中的任何一个类都可以实现一个接口,这个接口会影响到此类的所有子类,但不会影响到此类的任何超类。此类将不得不实现这个接口所规定的方法,而其子类可以从此类自动继承这些方法,当然也可以选择置换掉所有的这些方法,或者其中的某一些方法,这时候,这些子类具有了可插入性(并且可以用这个接口类型装载,传递实现了他的所有子类)。

接口提供了关联以及方法调用上的可插入性,软件系统的规模越大,生命周期越长,接口使得软件系统的灵活性和可扩展性,可插入性方面得到保证。

正是有了接口,使得Java单继承性有了新的扩展的可能(变向地实现多继承);
Java接口(以及抽象类)一般用来作为一个类型的等级结构的起点。

如果一个类已经有了一个主要的超类型,那么通过实现一个接口,这个类可以拥有另一个次要的超类型,这种次要的超类型叫做混合类型。

1、普通接口(含有方法定义)
public interface ActionListener {
  public abstract void actionPerformed(ActionEvent event);
}

2、标识接口(无任何方法和属性定义)标识接口是没有任何方法和属性的接口。
标识接口不对实现它的类有任何语义上的要求,它仅仅表明实现它的类属于一个特定的类型。
public interface Serializable{}

3、常量接口是指用Java接口来声明一些常量,然后由实现这个接口的类使用这些常量。
public interface AppConstants {
  public static final DATA_SOURCE_NAME="test";
  public static final USER_NAME="test";
  public static final PASSWORD="test";
}


------------------------------------------------------------

抽象类

在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:
abstract void fun();
抽象方法必须用abstract关键字进行修饰。

如果一个类含有抽象方法,则称这个类为抽象类(抽象类也可以没有抽象方法,这种用法主要是为了避免被实例化),抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。

抽象类中同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

1、抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2、抽象类不能用来创建对象;
3、如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。


-----------------------------------------------------------

Java接口和java抽象类对比:

相同点:
1、代表系统的抽象层,当一个系统使用一颗继承树上的类时,应该尽量把引用变量声明为继承树的上层抽象类型,这样可以提高两个系统之间的松耦合;
2、都不能被实例化;
3、都包含抽象方法,这些抽象方法用于描述系统能提供哪些服务,但不包含方法体;

不同点:
1、最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以;
2、单继承、多实现,Java接口是定义混合类型的理想工具;
3、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
4、接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:
声明类型的工作仍然由Java接口承担,但是同时给出一个Java 抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java 接口在最上面,然后紧跟着抽象类,这下两个的最大优点都能发挥到极至了。
这个模式就是“缺省适配模式”。

设计层面上的区别

  1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

  2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。


使用接口和抽象类的总体原则:

1、用接口作为系统与外界交互的窗口站在外界使用者(另一个系统)的角度,接口向使用者承诺系统能提供哪些服务,站在系统本身的角度,接口制定系统必须实现哪些服务,接口是系统中最高层次的抽象类型。

     通过接口交互可以提高两个系统之间的送耦合系统A通过系统B进行交互,是指系统A访问系统B时,把引用变量声明为系统B中的接口类型,该引用变量引用系统B中接口的实现类的实例。
  public interface B { }
  public class C implements B { }
  public class A { B a = new C(); }

2、Java接口本身必须非常稳定,Java接口一旦制定,就不允许随遇更加,否则对外面使用者及系统本身造成影响
3、用抽象类来定制系统中的扩展点,抽象类来完成部分实现,还要一些功能通过它的子类来实现

 

posted on 2016-07-21 15:41  alvin.zhang  阅读(122)  评论(0编辑  收藏  举报

导航