Java中的抽象类和接口的区别
本文主要列举Java语言中抽象类和接口的区别,不详细讲解接口和抽象类。
抽象类和接口.png
不知道大家有没有注意到,凡是问到某两个事物的区别,都会首先介绍它们的共同点,然后再介绍它们的区别,我们这里也不例外:
1、相同点
1.1. 接口和抽象类都不能被实例化
public interface Flyable { // 声明接口
}
public abstract class Flyer { // 声明抽象类
}
public class InstantiateTest {
public static void main( String[] args ){
Flyable a = new Flyable(); // 编译错误
Flyer b = new Flyer() ; // 编译错误
}
}
1.2. 接口和抽象类中都可以包含抽象方法
public interface Flyable {
public abstract void fly() ; // 默认都是 public abstract 所修饰
}
public abstract class Flyer {
public abstract void fly() ; // 必须显式指定 abstract 修饰符
}
1.3. 接口和抽象类中都可以包含非抽象的实例方法 ( 从Java 8 开始 )
public interface Flyable {
// 从 Java 8 开始可以在接口中声明 default 修饰的、非抽象的实例方法
public default void initialize() {
}
}
public abstract class Flyer {
// Java 类中本类就可以声明非抽象实例方法
public void initialize() {
}
}
1.4. 接口和抽象类中都可以包含类方法 ( 从Java 8 开始 )
public interface Flyable {
// 从 Java 8 开始可以在接口中声明类方法
public static void prepare() {
}
}
public abstract class Flyer {
// Java 类中本类就可以声明类方法
public static void prepare() {
}
}
1.5. 接口和抽象类中都可以包含私有方法 ( 从Java 9 开始 )
public interface Flyable {
// 从 Java 9 开始可以在接口中声明 private 修饰的非抽象方法
private void ready() {
}
private static void hello(){
}
}
public abstract class Flyer {
// Java 类中本类就可以声明私有方法
private void ready() {
}
private static void hello(){
}
}
1.6. 接口和抽象类中都可以包含常量
public interface Flyable {
// 接口中所有的常量默认都是 public static final
public static final String TYPE = "可飞行" ;
}
public abstract class Flyer {
// Java 类中本来就可以声明常量
public static final String TYPE = "飞行物" ;
}
1.7. 接口和接口、抽象类和其它类之间的继承都使用 extends 关键字实现
public interface Moveable {
}
// 接口继承接口
public interface Flyable extends Moveable {
}
public abstract class Flyer {
}
// 抽象类继承抽象类
public abstract class Plane extends Flyer {
}
// 具体类继承抽象类
public class Aircraft extends Flyer {
}
接口和接口之间的继承、抽象类和抽象类之间的继承,以及抽象类和具体类之间的继承都使用 extends 关键字实现。
2、区别
2.1. 所有的抽象类都是Object类的子类,而接口则没有默认的最顶层父接口
( 注意这个区别是最重要的区别之一,凡是没有说明这一点的,都是不合适的 )
// 除非通过 extends 关键字显式指定了接口的父接口,否则接口默认没有父接口
public interface Flyable {
// 接口中所有的常量默认都是 public static final
public static final String TYPE = "可飞行" ;
}
// 对于抽象类而言,若未显式使用 extends 指定其父类,则其父类为java.lang.Object类
// 如果通过 extends 关键字显式指定了抽象类的直接父类,则其java.lang.Object类为其间接父类
public abstract class Flyer {
}
2.2. 抽象类只能有一个直接父类,接口可以父接口直接继承多个接口
( 注意这个区别是最重要的区别之一,凡是没有说明这一点的,都是不合适的 )
public interface Liveable {
void live();
}
public interface Moveable {
void move();
}
// 接口可以一次继承多个接口
public interface Flyable extends Moveable , Liveable {
}
public abstract class Flyer {
}
// 类只能继承一个直接父类
public class Kites extends Flyer {
}
// 尝试让一个类继承多个直接父类会导致编译错误
public class Airship extends Flyer , Object { // 编译错误
}
2.3. 抽象类有构造方法,接口没有构造方法
( 注意这个区别是最重要的区别之一,凡是没有说明这一点的,都是不合适的 )
- 抽象类首先是个类,是类就一定有构造方法:
public abstract class Flyer {
public Flyer() { // 显式声明的无参构造
super();
}
}
如果没有显式书写构造方法,编译器也会为抽象类添加一个公开的
、无参的
构造方法。
抽象类中的构造方法是供其直接子类
调用的,并不是为了直接创建抽象类本身的实例准备的。
- 接口不是类,接口没有构造方法
public interface Flyable {
// 尝试为接口添加构造方法会导致编译错误
public Flyable() { // 编译错误
}
}
2.4. 接口中的成员变量只能是常量,抽象类中的成员变量可以是常量也可以是非常量
( 注意这个区别是最重要的区别之一,凡是没有说明这一点的,都是不合适的 )
public interface Flyable {
// 接口中所有的成员变量默认都是 public static final 修饰的
String TYPE = "可飞行" ; // 这里省略了 public 、static 、final 三个修饰符
String name ; // 编译错误 ( 因为默认有 final 修饰,必须显式赋值 )
}
public abstract class Flyer {
public static final String TYPE = "飞行物" ; // 常量
private static final String ENGINE = "引擎" ; // 常量
public static String brand ; // 类变量
private String name ; // 实例变量
}
2.5. 抽象内容不同
从OOAD角度看,抽象类是对某一类事物的抽象,是设计具体类的模板(属于数据结构范畴);
接口是对行为的抽象(属于行为规范范畴),实现该接口就表示该类事物可以具有某种行为特征。
2.6. 其它区别
- 接口中的抽象方法必须是
public
访问级别,抽象类中的抽象方法可以是public
、protected
、package-private
等访问级别 - 接口中的非抽象实例方法必须是
default
修饰符修饰,而抽象类中的非抽象实例方法一定不能用default
修饰符修饰 - 抽象类可以继承(
extends
)指定父类并实现(implements
)指定接口,接口只能继承(extends
)接口(不能继承任何类)
如果以上区别也非要当作重大区别的话,那么还可以赠送两个区别:
- 接口使用
interface
关键字声明,抽象类使用class
关键字声明并使用abstract
修饰 - 汉语中,接口是两个字,抽象类是三个字; 英语中,
interface
是一个词,abstract class
是两个词。并且不论汉语还是英语,每个字/每个词的写法都不一样。
因为写作时间仓促,错误和不当之处是在所难免的,欢迎大家批评指正!
写作背景:
2008年被某浪删过几次博客后,后来很少写或者几乎不写博文,仅有的几篇公开的博文,也是为学生整理的学习笔记。
所以,原本不打算在简书发任何文章,仅仅作为一个看客,看看大家写的文章,必要的时点评一下,跟大家做个交流就好。
无奈最近几天看到一篇文章,标题是《接口(interface)和抽象类(abstract class)的区别是什么》,这边文章并没有抓住接口和抽象类的主要区别,因为写的挺像回事的,所以好多人继续照抄了这篇文章,导致两三天的时间里能多次看到名称相同、内容相同的文章。
将别人整理的文章为我所用是可以的,关键是你得琢磨琢磨他写的对不对,最要命的是给他们点评后,他们根本不予理会,甚至把给它们的评论直接删除了。
为了避免有更多的后来者以讹传讹,所以写了这片博文。
因为写作时间仓促,错误和不当之处是在所难免的,欢迎大家批评指正!