Java的抽象类和接口
抽象类和接口是两个容易混淆的概念,但有一句话能很好地将这两者区分开来,即抽象类是事物的抽象,而接口是行为的抽象。抽象类抽象出来的是一类事物,事物中包含了一些固有的属性和行为,而接口更多的是提供固有属性行为之外的延伸行为。打个比方,可以把动物看成为抽象类,类中有一些固有属性,如身高体重,还有一些共有行为,如吃饭和睡觉,所有的动物都遵循着这些属性和行为。除此之外,有些动物还能飞,但并不是所有的动物都具有飞行这种能力,此时飞行只是事物的延伸功能,相当于一个接口。
一.抽象类
抽象类是包含抽象方法的类。抽象方法是一种特殊的方法,抽象方法的声明格式为:
abstract void fun()
抽象类有以下三个主要的特点:
1)它只有声明,没有具体的实现。抽象类和抽象方法都必须用abstract关键字来描述。
2)抽象方法的具体实现由子类来完成,若子类不实现父类中的抽象类,则该子类同样需要定义为抽象类。因此抽象方法的访问修饰符只能是public和protected,这个很好理解,若访问权限为private则继承该抽象类的子类无法具体该方法。
3)抽象类不能实例化。因为抽象类中的抽象方法没有具体实现,实例化后调用该方法没有具体操作。若想调用抽象类中的非抽象方法,可以实例化抽象类的子类继而进行调用。(当然,前提是子类不是抽象类)
另外,尽管抽象类的定义是包含抽象方法的类,但并不意味这抽象类中只能有抽象方法。和普通类一样,抽象类中可以拥有成员变量和普通的成员方法。
抽象类相对于普通类的三点区别:
1)抽象方法必须为public或protected(如果是private则无法被子类继承,进而实现方法),缺省情况下默认为public
2)抽象类不能实例化
3)如果一个类继承于抽象类,则子类必须实现父类的抽象方法,否则该子类同样为abstract类
二.接口
修饰词为interface,在软件工程中,接口泛指供别人调用的方法,因为我们也能初步体会Java语言设计者的初衷,即接口是延伸行为的抽象。接口的声明格式为:
public interface interfaceName
{
}
接口有以下三个特点:
1)接口是可调用的。这也是接口存在的意义
2)接口中的变量会被隐式地指定为public static final(并且只能是public static final,用private编译会报错)。但是接口中一般不定义变量(既然所有的方法都没有具体实现,定义了变量也无处可用)
3)方法会被隐式地指定为public abstract,就是说接口中所有的方法都是抽象方法。而由此可看出接口和抽象类的一个区别,接口是极度的抽象。
实现接口需要用implements关键字,格式为
class className implements Interface1, Interface2,...
{
}
由此可以看出接口与抽象类的另一个区别,一个类只能继承一个抽象类,却可以实现多个接口。当一个类实现一个接口时必须实现该接口的所有抽象方法(该实现类为抽象类时例外)
三.抽象类和接口的区别
参数 | 抽象类 | 接口 |
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的。它根本不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
四.抽象类和接口的使用指导
下面先来看看网上流传最为广泛的例子:门和警报的例子。门和警报都有open()和close()两个动作,此时我们可以通过抽象类和接口来定义这个抽象概念:
public abstract class Door
{
public abstract void open();
public abstract void open();
}
public 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接口
public interface Alarm
{
public abstract void alarm();
}
public abstract class Door
{
public abstract void open();
public abstract void close();
}
public class AlarmDoor extends Door implements Alarm
{
public void open(){}
public void close(){}
public void alarm(){}
}
由此可以总结得出:
1)如果你想拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类。
2)如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
3)如果基本功能在不断改变,那么就需要使用抽象类。否则一旦需要修改某个接口,就必须相应的修改该接口的所有实现
参考文献
http://www.cnblogs.com/dolphin0520/p/3811437.html
http://www.importnew.com/12399.html