对于面向对象编程来说,抽象是其一大特点。在Java中,OOP的抽象可以体现为两种形式:接口和抽象类。两者之间有很多相似之处,也有很多不同之处。很多人在初学者的时候都认为它们可以随意互换使用,其实不然。今天我们将学习Java培训和学习中的接口和抽象类。1.抽象类在了解抽象类之前,我们先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,没有具体的实现。抽象方法的声明格式为:abstractvoidfun();必须使用abstract关键字修饰抽象方法。如果一个类包含抽象方法,则该类称为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类包含没有具体实现的方法,所以不能使用抽象类创建对象。这里有一个问题需要注意:在《JAVA编程思想》一书中,抽象类被定义为“包含抽象方法的类”,但是后来发现如果一个类不包含抽象方法,那么它也是一个抽象类如果它只用抽象修饰。也就是说,一个抽象类并不一定要包含抽象方法。我个人认为这是一个死胡同的问题,因为如果一个抽象类不包含任何抽象方法,为什么要设计成抽象类呢?所以暂时记住这个概念,不必深究原因。[公共]抽象类ClassName{abstractvoidfun();}由此可见,抽象类是为继承而存在的。如果你定义了一个抽象类却不去继承它,那么就相当于白白创建了这个抽象类。类,因为你不能用它做任何事情。对于一个父类来说,如果在父类中实现一个方法没有任何意义,必须根据子类的实际需要进行不同的实现,那么这个方法可以声明为抽象方法,这个类也它成为一个抽象类。包含抽象方法的类称为抽象类,但并不是说抽象类中只能有抽象方法。它也可以像普通类一样有成员变量和普通成员方法。注意抽象类和普通类的主要区别有3个:1.抽象方法必须是public或者protected(因为如果是private就不能被子类继承,子类也不能实现该方法),默认是民众。2.抽象类不能用来创建对象;3.如果一个类继承自抽象类,子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,那么子类也必须定义为抽象类。在其他方面,抽象类与普通类没有区别。2.接口接口,英文称为interface,在软件工程中,接口一般是指一种方法或函数,供他人调用。从这里,我们可以体会到Java语言设计者的初衷,就是对行为的抽象。在Java中,定义接口的形式如下:[public]interfaceInterfaceName{}接口可以包含变量和方法。但是需要注意的是,接口中的变量会被隐式指定为publicstaticfinal变量(而且只能是publicstaticfinal变量,private修改会报编译错误),而方法会被隐式指定为publicabstractmethods和只能是public抽象方法(用其他关键字修饰,如private、protected、static、final等会报编译错误),接口中的所有方法不能有具体的实现,也就是说接口中的方法必须都是抽象方法。从这里,我们可以隐约看出接口和抽象类的区别。接口是一种极其抽象的类型,比抽象类更“抽象”,一般不会在接口中定义变量。要使类遵循一组特定的接口,您需要使用implements关键字。具体格式如下:classClassNameimplementsInterface1,Interface2,[....]{}可见,允许一个类遵循多个特定的接口。如果一个非抽象类符合一个接口,则必须实现该接口中的所有方法。对于遵循接口的抽象类,接口中的抽象方法可能不会被实现。三、抽象类和接口的区别1.语法层面的区别抽象类可以提供成员方法的实现细节,而接口中只能存在公共抽象方法;抽象类中的成员变量可以是多种类型,而接口中的成员变量只能是publicstaticfinal类型;接口不能包含静态代码块和静态方法,抽象类可以有静态代码块和静态方法;一个类只能继承一个抽象类,但是一个类可以实现多个接口。2、设计层面的区别1)抽象类是对事物的抽象,即对类的抽象,而接口是对行为的抽象。抽象类将整个类抽象为一个整体,包括属性和行为,而接口则抽象类的部分(行为)。举个简单的例子,飞机和鸟是不同的东西,但是它们都有一个共同点,那就是都会飞。那么在设计的时候,你可以把飞机设计成Airplane-like,把鸟设计成Bird-like,但是不能把flight这个特性设计成一个类,所以它只是一个行为特性,不是抽象描述一类东西。.此时可以将flight设计为一个接口Fly,包括方法fly(),然后Airplane和Bird根据自己的需要实现Fly接口。那么对于不同类型的飞行器,比如战斗机,民用飞机,直接继承Airplane就可以了。鸟类也是如此。不同种类的鸟可以直接继承Bird类。从这里可以看出,继承是一种“有无”的关系,而接口实现则是一种“有无”的关系。如果一个类继承了某个抽象类,那么子类一定是抽象类的类型,接口实现与它有没有有关,比如鸟会不会飞(或者说它有没有飞的特性),能飞那就实现这个接口就可以了,如果不能飞就不要实现这个接口。2)设计层次不同。抽象类作为很多子类的父类,是一种模板设计。虽然界面是一种行为规范,但它是一种放射状设计。什么是模板设计?最简单的例子,ppt中的模板大家都用过。如果你用模板A设计pptB和pptC,pptB和pptC的共同部分就是模板A,如果他们的共同部分需要改,只需要改模板A就可以了,没有需要重新修改pptB和pptC。而放射状设计,比如某部电梯安装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说,对于一个抽象类,如果需要增加新的方法,可以直接在抽象类中增加具体的实现,不需要改变子类;但是对于接口来说,如果改变了接口,那么接口类的所有实现都必须做相应的修改。我们来看一个网上流传最广的例子:门和报警器的例子:门有开()和关()两个动作,这时候我们可以通过抽象类和接口来定义这个抽象概念:abstract门类{公共抽象无效开放();公共抽象无效关闭();}或者:interfaceDoor{publicabstractvoidopen();公共抽象无效关闭();但是现在如果我们需要门具有报警功能,那么如何实现呢?下面提供两个思路:1)将这三个功能放在抽象类中,但是这样子继承这个抽象类的所有子类都有报警功能,但是有的门不一定有报警功能;2)将这三个函数都放在界面中。需要使用报警功能的类需要在该接口中实现open()和close()。也许这个类根本没有open()和close()。两种功能,如火警。从这里可以看出,Door的open()、close()和alarm()属于两类不同的行为。open()和close()属于门本身固有的行为特征,而alarm()则属于Extended附加行为。所以,最好的方案是将alarm单独设计成一个接口,包括alarm()的行为,将Door设计成一个单独的抽象类,包括open和close两个行为。然后设计一个报警门,继承Door类,实现Alarm接口。接口Alram{voidalarm();}抽象类Door{voidopen();无效关闭();}classAlarmDoorextendsDoorimplementsAlarm{voidoepn(){//....}voidclose(){//....}voidalarm(){//....}}最后,使用一个表总结一下抽象类和接口的区别:
