Java抽象类与接口的总结

来源:互联网 发布:android网络抓包工具 编辑:程序博客网 时间:2024/06/03 16:31

最近学到抽象类和接口的知识,看了李兴华老师讲解的视频及一些前辈博客,这里做一下总结,方便以后复习

抽象类和接口是整个Java面向对象的核心部分,他们之间有共性也有区别,下面主要从以下方面逐一总结

一.抽象类

抽象方法:只声明而未实现(没定义方法体)的方法称为抽象方法,抽象方法必须使用abstract关键字声明

abstract void fun();

抽象类:如果一个类中包含抽象方法,那么此类就是抽象类,抽象类也必须使用abstract关键字声明,抽象类是为继承而生,所以必须要有子类继承,不然没意义

abstract class Demo{      //抽象类String name;public void print(){System.out.print("hello");}abstract void fun();  //抽象方法}

抽象类和普通类相比,只是增加了抽象abstract class的声明,和增加了抽象方法而已,其他的属性、方法定义结构都一样。

但是抽象类不能被实例化,也就是说,如果把一个类声明为abstract,那么该类不能创建对象,因为抽象类中的抽象方法没有实现,调用没有意义。如下:

abstract class Demo{      //抽象类String name = "Jack";public void print(){System.out.print("hello");}abstract void fun();  //抽象方法}public class AbstractDemo{public static void main(String[] args){Demo demo = new Demo();}}
是错误的,不能创建抽象类的对象。虽然不能创建抽象类的对象,但是却可以定义一个抽象类的对象变量,然后引用非抽象子类的对象。

好比我们定义一个宠物抽象类,让小猫继承它,虽然我们不能创建宠物的对象,但是可以创建小猫对象,让宠物引用指向小猫对象,如下:

abstract class Pet{      //抽象类abstract void eat();  //抽象方法}class Cat extends Pet{public void eat(){System.out.println("吃肉");}}public class AbstractDemo{public static void main(String[] args){Pet pet = null;   //定义抽象类的对象变量pet = new Cat();  //创建非抽象子类的对象pet.eat();}}

还需注意的是:

1.一个类即使没有抽象方法,也可以声明为抽象类,这样做的目的只是为了不让该类创建对象。

2.抽象类必须要有子类,并且子类要覆写所有的抽象方法,否则该子类还是一个抽象类。

3.抽象类不能声明为final,因为final声明的类不能有子类,而抽象类必须要有子类,矛盾。

4.抽象方法不能声明为private,因为private声明的方法不能被子类继承,子类无法实现此方法。抽象方法默认为public

另外,抽象类虽然不能实例化,但可以定义构造方法,因为抽象类有子类 ,子类在实例化之前会先实例化父类,调用其构造方法,当然也可以通过super显示调用

abstract class Pet{      //抽象类public Pet(){System.out.println("抽象类构造方法");}abstract void eat();  //抽象方法}class Cat extends Pet{public Cat(){System.out.println("子类构造方法");}public void eat(){System.out.println("吃肉");}}public class AbstractDemo{public static void main(String[] args){Pet pet = null;   //定义抽象类的对象变量pet = new Cat();  //创建非抽象子类的对象pet.eat();}}


二.接口

当一个类中全部是由抽象方法和全局常量组成的时候,就可以将这个类定义成一个接口了,接口使用interface关键字声明

interface Demo{public static final String NAME = "Jack";public abstract void print();}

对于接口来讲,因为其在定义的时候已经确定了其由全局常量和抽象方法组成,所以可以简化:

interface Demo{String NAME = "Jack";void print();}
编译时会自动加上修饰关键字。

另外注意:所有的修饰符在接口中是否添加本身是没有任何意义的,而且接口中的方法全部都属于公共的方法操作(public)。

接口的使用中必须有子类,子类必须覆写全部抽象方法,通过implements实现。

1.一个子类可以实现多个接口,如下

class 类名 implements 接口A,接口B,[......]{}

interface A{String INFO = "hello world";void print();}interface B{void info();}class C implements A,B{public void print(){System.out.println("INFO = "+INFO);}public void info(){}}public class InterfaceDemo{public static void main(String[] args){C c = new C();c.print();}}

2.一个子类可以同时继承抽象类并实现接口,而且必须先继承抽象类之后再实现接口

class 类名 extends 抽象类 implements 接口A,接口B,[......]{}

abstract class A{public String INFO = "hello world";abstract void print();}interface B{void info();}class C extends A implements B{public void print(){System.out.println("INFO = "+INFO);}public void info(){}}public class InterfaceDemo{public static void main(String[] args){C c = new C();c.print();}}

那么该子类需要覆写抽象类和接口的所有抽象方法。

3.一个抽象类可以实现接口,那么该抽象类的子类必须同时覆写抽象类和接口的所有抽象方法,注意与第二点的区别

abstract class A implements B{public String INFO = "hello world";abstract void print();}interface B{void info();}class C extends A{public void print(){System.out.println("INFO = "+INFO);}public void info(){}}public class InterfaceDemo{public static void main(String[] args){C c = new C();c.print();}}
本质上和第二点是一样。
4.一个接口可以同时继承(extends)多个接口


interface A{String INFO = "hello world";void printA();}interface B{void printB();}interface C extends A,B{ void printC();}class D implements C{public void printA(){}public void printB(){}public void printC(){}}
注意:类实现(implements)接口,接口继承(extends)接口
三.抽象类和接口的区别

这部分参考了前辈:

http://www.cnblogs.com/dolphin0520/p/3811437.html

http://peiquan.blog.51cto.com/7518552/1271610

的博文

用法上的区别:

1.接口里面不能定义静态方法,抽象类可以定义静态方法

2.接口里不包含初始化块,抽象类可以包含初始化块

3.接口里不含有构造方法,抽象类可以包含构造器。抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

4.接口里不能包含已经实现的方法,只能有抽象方法,而抽象类可以同时包含

5.接口里只能声明静态常量,抽象类可以定义普通变量,也可以定义静态常量

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

设计上的区别:

抽象类所代表的是“is-a”的关系,而接口所代表的是“like-a”的关系。

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() {      //....    }}
参考资料:

李兴华JAVA视频讲解
http://www.cnblogs.com/dolphin0520/p/3811437.html

http://peiquan.blog.51cto.com/7518552/1271610

http://dev.yesky.com/436/7581936.shtml


1 0
原创粉丝点击