抽象类和接口理解

作者: shenshizhong | 来源:发表于2016-09-19 11:58 被阅读480次

    abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。

    抽象类:

    所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

    抽象类是是用来捕捉子类的通用特性的,是一种模板,它不能被实例化,只能被用作子类的超类。抽象类必须在类前用abstract关键字修饰。抽象类不能实例

    只要包含一个抽象方法的类,该类必须要定义成抽象类

    抽象类的目的:

    1,  抽象类就是为了继承而存在的,为子类提供一个公共的类型;

    2,  封装子类中的重复内容(成员变量和方法);

    3,  定义抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。

    抽象类中包含抽象方法,抽象方法的声明格式为

    public abstract void cry();

    抽象方法是一种特殊的方法:它只有声明,而没有具体的实现

    抽象类例子:

    public abstract class Animal {

    public abstract void cry();

    }

    子类继承例子:

    public class Dog extends Animal{

    @Override

    public void cry() {

    System.out.println("狗叫...");

    }

    }

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

    1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

    2)抽象类不能用来创建对象(不能被实例);因为抽象类中含有无具体实现的方法

    3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。(抽象类可以继承抽象类)

    接口(interface):

    接口泛指供别人调用的方法或者函数,它是对行为的抽象。接口是抽象的抽象。

    接口是抽象方法的集合,是一种形式,一种标准,就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口中的方法必须都是抽象方法,并且接口中所有的方法不能有具体的实现,接口中成员变量只能是public static final这种形式,相当于常量,不可以修改的(一般不在接口中定义成员变量)

    方法只能为public,当然你可以显示的声明为protected、private,但是编译会出错

    注意点:实现类必须要实现该接口的所有方法

    接口的使用,需要使用implements关键字,具体格式如下:

    class ClassName implementsInterface1,Interface2,[....]{

    }

    接口的例子:

    interface Door{

    void open ();

    void close();

    }

    子类中实现接口:

    Public class BigDoor implements Door {

    void open (){

    //实现

    };

    void close(){

    //实现

    };

    }

    抽象类与接口的区别:

    一、语法层面上的区别:

    1.      抽象类可以多种修饰方法,接口中只能存在public abstract 方法

    2.      一个类只能继承一个抽象类,而一个类却可以实现多个接口

    二、设计层面上的区别

    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进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

    下面看一个最广泛的例子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

    abstract class Door {

    public abstract void open();

    public abstract void close();

    }

    或者:

    interface Door {

    public abstract void open();

    public abstract void close();

    }

    但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:

    1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;

    2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

    从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

    interface Alram {

    void alarm();

    }

    abstract class Door {

    void open();

    void close();

    }

    class AlarmDoor extends Door implements Alarm {

    void oepn() {

    //....

    }

    void close() {

    //....

    }

    void alarm() {

    //....

    }

    }

    两者正确使用方式:

    宏观上讲:

    抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么,具备什么。

    抽象类使用:比如,男人,女人,这两个类,他们的抽象类是人。说明,他们都是人。

    接口使用:比如,人可以吃东西,猫也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.

    当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

    具体注意点:

    1、如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。

    2、如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。

    3、如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

    ISP(Interface Segregation Principle)接口隔离原则(面向对象的一个核心原则):

    1、  它表明使用多个专门的接口比使用单一的总接口要好。

    2、  一个类对另外一个类的依赖性应当是建立在最小的接口上的。

    3、   一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

    总结:

    1、一个类只能继承一个抽象类,但是可以实现多个接口。

    2、 在抽象类中可以拥有自己的成员变量和非抽象类方法,但是接口中只能存在静态的不可变的成员数据(不过一般都不在接口中定义成员数据),而且它的所有方法都是抽象的。

    接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的

    3、抽象类和接口所反映的设计理念是不同的,抽象类所代表的是“is-a”的关系,而接口所代表的是“has-a”的关系。

    4、实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。

    相关文章

      网友评论

      • 枫_8288:再形象描述一下、抽象就像亲爹,只能有一个,接口就像干爹,可以有多个,他的资源你基本可以使用~~~:smile:
      • timloong:没有抽象方法也可以定义成抽象类~😬
      • Heartsxin:例子很生动形象
      • 9c793c55195d:好文!

      本文标题:抽象类和接口理解

      本文链接:https://www.haomeiwen.com/subject/svxnettx.html