我们在上一章中介绍了什么是接口,也说到了接口就是一组抽象的数据模型,可以理解为一组协议。但实际上,在面向对象的概念中,有一个知识点是极容易被人与接口混淆的,人们往往会误解为这两者是同一个概念。但不幸的是,两者虽然有相似之处,但却是完全不一样的概念。那么,如此神秘的它到底是什么呢?让我们揭开它的盖头来—主角登场–>抽象类。 什么叫抽象类呢?从语义而言,抽象类的意思是指类的抽象体。什么意思呢?我们知道类是对具体事物的抽象,但是有的时候,有一些类的信息不足以去描绘出一个具体的对象,那么这些类就叫做抽象类。什么意思呢?就好比现在有三角形类,四边形类,八边形类。它们的形状都是不一样的。但是它们又都可以叫做图形,只是每个类的画法是不一样的而已。那么,在这里,我们就可以构建一个叫做图形的抽象类,然后在里面添加一个叫做画图的抽象方法,然后让三角形类,四边形类,八边形类去继承这个抽象类,再重写这个画图方法。比如:
package testabstractclass; /** * 测试入口 */ public class Test1 { public static void main(String[] args) { Triangle triangle = new Triangle(); Quadrilateral quadrilateral = new Quadrilateral(); } } /** * 继承了抽象类的三角形类 */ class Triangle extends ABSGraph{ public Triangle(){ System.out.print("我是三角形-->"); draw(); } @Override public void draw() { System.out.println("三角形画法"); } } /** * 继承了抽象类的四边形类 */ class Quadrilateral extends ABSGraph { public Quadrilateral() { System.out.print("我是四边形-->"); draw(); } @Override public void draw() { System.out.println("四边形画法"); } } /** * 抽象类 */ abstract class ABSGraph{ //抽象方法 public abstract void draw(); }运行后,效果如下:
注意的是:一但在抽象类中声明了抽象方法,那么就必须要在子类中实现该方法,这点和接口是相似的。但和接口不同的是,抽象类中是可以存在具体的实现方法,并且该方法是可以不被子类实现而直接调用的。比如:
package testabstractclass; /** * 测试入口 */ public class Test1 { public static void main(String[] args) { Triangle triangle = new Triangle(); //直接调用抽象类的具体方法 String name =triangle.GetName(); System.out.println(name); } } class Triangle extends ABSGraph{ public Triangle(){ System.out.print("我是三角形-->"); draw(); } @Override public void draw() { System.out.println("三角形画法"); } } abstract class ABSGraph{ //抽象方法 public abstract void draw(); //具体办法 public String GetName() { return "ABSGraph是抽象类"; } }运行结果如下:
从以上两点可以得出,其实抽象类和普通的类在语法上是很相似的,只是在标志符上用了abstracrt关键字来标明类。实例如下:
abstract class AbsClass{ //抽象办法,注意抽象办法不需要写方法体,同接口一样 public abstract int absMethodName(); //具体办法,同普通类一样 public int comMethodName(){ return 0; } }那么,抽象类和普通类有什么不一样的地方呢?主要有三点:
1.抽象类不能直接初始化对象,必须创建一个子类去继承,并且实现抽象类中的所有抽象方法 2.抽象类不能用private关键字标识类体或抽象方法 3.抽象类允许包含抽象成员(但没有强制要求)注意:针对第一点,有一个地方容易让人混淆,事例如下: 有人可能会疑虑:不是说抽象类不能直接初始化对象吗?怎么在这个例子里面又可以呢?其实,这个问题在讲到内部类的时候,就已经说到了。在这个例子里,抽象类并没有直接初始化一个对象,而是通过一个匿名内部类继承了ABSGraph,实现了抽象方法之后,再将其向上转型为 ABSGraph类型的triangle对象。其中涉及了多态及内部类的相关知识点。同时,因为接口也可以作为匿名内部类的继承方式,所以这里也容易被人与接口进行混淆。 那么,既然我们说抽象类容易被人与接口进行混淆,那么他们之间有什么区别呢?我们来看看:
1.从继承方式来看,一个子类只可以继承一个父类(不管是具体类还是抽象类),但可以继承多个接口 2.抽象类可以实现方法的细节,但是接口是不允许存在的。这表现为:如果有两个子类继承了抽象类。那么当有需求进行更改的时候,我们只需要更改抽象类而不同更改它的子类。这等于一种模板式的设计。我们确定好了模板之后,所生产的产品是不需要再做改动的。但是如果两个自己实现了接口,当接口发生了改变时,那么它的子类是需要发生相应的改变的。这是一种辐射性设计,当协议发生改变的时候,其子类必须修改自身去适应这个协议的要求。因此,我们也说抽象类就是模板,而接口就是协议。 3.接口中不能含有静态的方法,而抽象类中允许 4.接口默认所有的方法为public abstract final类型,而接口的方法可以自定义。至此,关于抽象类的介绍就到此结束了,学习抽象类最主要的地方就是理解好它和普通类以及它和接口的区别在哪。因为通过这些比对,你才能更容易去理解什么是模板设计,什么是辐射设计。抽象类为什么是对事物的抽象,接口为什么是对行为的抽象。为什么说接口的层次比抽象类更高等等。对于抽象类的运用,多使用在模式设计上,比如抽象工厂模式。但不可置疑的是,抽象类和接口是最能体现面向对象编程的思想的。因此,对抽象类有一个比较清晰的了解。会让你在学习面向对象的路上走得更远哦。 好了,我们下一章的内容是:Java-面向对象编程-几个关键字,敬请期待。如对本章内容有所疑问,可在下方评论探讨。