【Java】接口和抽象类的区别?
文章目录
【简要回答】
相同点:
1.可以定义抽象方法
2.不能创建本类对象,只能由子类去实例化子类对象
不同点:
1.子类实现:implements;子类继承父类:extends
2.抽象类可以继承接口;接口只能继承接口,不能继承类。一个类只能继承一个父类,但可以实现多个接口
3.抽象类可以定义成员属性,接口不能定义成员属性。(接口没有了成员属性,只有方法,只能用static final关键字定义静态常量,不能定义静态变量。子类实现接口后,只能重写方法;子类继承抽象类,连带着父类的成员属性也继承过来了)
4.抽象类有构造器,接口没有构造器。(抽象类的构造器作用:限定子类的构造行为,例如)
版本差异:
Java8:接口
1.可以定义静态方法
2.用default关键字实现方法(default关键字修饰的方法,不是抽象方法,不强制要求子类实现方法,保证向前兼容)
Java9:接口
1.能在接口中使用private方法(加入default关键字后代码不好维护,加入private后将内部逻辑拆开放在内部)
使用场景:
1.当既可以用接口也可以用抽象类,尽量选择接口,灵活度更高
2.当需要子类继承成员变量或者需要控制子类的实例化(构造器中定义固定数量的参数)
最后一段话总结。
【详细回答】
接口的诞生:
接口是如何诞生的?这我从头捋捋:
类和对象:
假设现在是一个没有对象,只有基本数据类型和函数的世界,当我们的数据和函数多了,维护起来就会越发困难,于是我将其中一些有关联性质的数据和函数封装起来,类和对象就这么诞生了。
我只需要创建一个对象,就拥有了特定的属性和方法。这些属性和方法,都聚合在了一个实例上,维护起来比较方便。
继承:
可还有一个问题,现在大多数类的属性和方法都差不多,完全没必要每次都重新定义,于是将这些重复的东西封装到一个类中,其他类只需要复用他即可。继承就这么诞生了。
多态:
子类继承了父类之后,便拥有了父类的属性和方法,同时可以拓展自己的特性。
我们经常定义一个父类,然后接收多个子类,在程序执行的时候,能自行发挥各自子类的特性。
这一机制就是我们讲的多态。
抽象类:
很多时候我们发现,父类完全没必要实现所有逻辑,也没必要创建父类对象,因为我们就是想让各种各样的子类来完成不同的逻辑。
这时候我们就可以将父类的方法抽象出来,抽象类就这么诞生了。
接口:
这里的抽象类其实就已经有标准和规范的意思,抽象方法就可以理解为一个对外的标准,子类就是这些标准的实现方。
然后我们会发现,抽象类还不算彻底的抽象,因为他除了抽象方法外,还有成员属性。
可我们很多时候就是想定制一个纯粹的标准,让子类去实现抽象方法,不想让子类再继承别的东西,于是我们将抽象类更进一步地抽象,接口就诞生了。
接口只有方法,没有成员属性,子类继承接口后,唯一能做的就是重写方法。
所以说,接口就是一种标准的规范,他规定好方法模板后,子类都得按照这个来实现。
因此接口在程序中的作用就是定义方法、让子类实现,然后供调用方调用。
映射到生活中,子类就是设备厂商,接口调用方就是用户,只管使用,而不用操心各个设备的差异。
实际操作中的接口:
当我们想操作多个拥有共性的对象时,就可以用到接口,比如,我想打印一个数据集,就可以用到java的collection接口,我将方法参数定义为collection,别人就可以传任何collection子类进来,ArrayList可以,HashSet也可以,我根本不用关心数据是用哪个集合存储的,collection有上百个子类,别人爱用哪个就用哪个,都不会影响我的打印逻辑。
抽象类和接口的异同:
抽象类和接口都是为了将方法进行抽象,然后让子类去实现。
public abstract class Animal{
public abstract void eat();
}
public interface Runnable{
public abstract void run();
}
相同一:可以定义抽象方法
所以可以定义抽象方法,就是两者第一个相同点。
相同二:不能创建本类对象
第二个相同点是不能创建本类对象,也就是这种父类是没有必要去创建实例对象的。只能由子类去实例化子类对象。
差异一:子类拓展时的关键字不一样
这里他们有个明显的差异点,就是子类要拓展他们时,对抽象类用的是extends关键字,我们称之为继承。
接口用的是implements关键字,我们称之为实现。这只是关键字和称呼的不同,本质都一样。
public class Dog extends Animal{}
public class Thread implements Runnable{}
然后,抽象类可以去实现接口,接口只能继承接口,不能继承类。
public abstract class Animal implements A{}
public interface Runnable extends A,B,C{}
同时,一个类最多只能继承一个父类,但可以实现多个接口。
public abstract class Pet extends Animal implements A,B,C{}
所以,当我们发现既可以用抽象类,也可以用接口时,尽量选择用接口,这样子类的灵活度会更高。
差异二:抽象类可以定义成员属性,而接口不能定义成员属性
抽象类更进一步的抽象后,就诞生了接口,接口比抽象类更纯粹,因为他没有了成员属性,只有方法。
子类实现接口后,唯一能做的就是重写方法。不像抽象类,子类继承抽象类之后,连带着将父类的成员属性也继承过来了。
这里就是两者的又一差异点:抽象类可以定义成员属性,而接口不能定义成员属性,只能定义静态属性,而且只能用final关键字定义静态常量,不能定义静态变量。
接口除了没有成员属性外,还没有构造器,可以说是非常纯粹了。
public abstract class Animal{
protected String name;
public abstract void eat();
}
public interface Runnable{
public static final String CRAB="螃蟹";
public abstract void run();
}
说白了,接口就是一个只有方法和静态常量的类。
这里你可能会有疑惑,抽象类都不能被实例化,还要构造器有啥用呢?
public abstract class Animal{
protected String name;
protected Animal(String name){
this.name=name;
}
public abstract void eat();
}
class Dog extends Animal{
public Dog(String name){
super(name);
}
@Override
public void eat(){
System.out.println(name+"要开吃了~");
}
}
他的用处就是:限定子类的构造行为。
比如,抽象类可以将构造器定义好几个参数,子类要想实例化则必须想办法传入这几个参数才行,两者的异同就讲完了。
一些重要的版本差异:
接口在java8之前更加纯粹,那时接口只能定义抽象方法,不能自己实现方法,也不能定义静态方法。
到了java8,才可以定义静态方法,以及可以用default关键字来实现方法。
public interface Runnable{
void run();
default void defaultMethod(){
System.out.println("default 方法");
static void staticMethod(){
Syste.out.println("静态方法");
}
}
}
这里不要死记硬背,一定要求理解Java设计者背后的意图,为什么突然在Java8加了这个特性呢?
因为Java8许多原有的接口新增了很多方法,这些新增的方法,会影响到之前的子类。
如果你继承了某个接口,突然接口新增了一个方法,而你没有去实现,你的子类就会编译失败。
为了保证向前兼容,Java8就推出了default关键字,被default关键字修饰的方法,就不是抽象方法了。
也就不会强制要求已有的子类去实现方法。
default方法出现后,大家发现还挺好用,就大量在接口在去实现一些默认逻辑。
public interface Runnable{
void run();
default void defaultMethod(){
privateMethod();
privateMethod();
privateMethod();
}
private void privateMethod(){
System.out.println("私有方法");
}
}
可是一个方法中实现复杂逻辑,就会导致代码难以维护,于是Java9又推出了一个新特性,那就是能在接口中定义private方法,
这样就可以将一些内部逻辑拆开了,可以发现,越到后面,抽象类和接口的差异也就越小。
那什么时候改用抽象类,什么时候改用接口呢?
当你需要让子类继承成员变量,或者需要控制子类的实例化时,你就用抽象类,否则,你就用接口。
只要记住,接口是更加纯粹的抽象类,就能理解两者的异同。
纯粹就代表着精简,接口比抽象类少了成员属性和构造器,只留下了静态常量和方法,更能体现标准和规范的含义,这也是我们为什么经常说:要面向接口开发。
一段话总结:
接口更关注“规范”,就是一种“约束”——你实现了这个接口,就必须保证这些行为存在;不提供复用逻辑,纯粹就是规范。
抽象类更关注代码复用,让多个子类复用属性和通用方法,提升开发效率;抽象类的主要目的是将“共性抽取为模板”,减少重复代码。
需要补充的是:接口在 Java 8 之后有了 default 方法,也可以提供一定程度的代码复用。
【掌握程度】
●能够清晰地定义接口和抽象类:解释它们的基本定义和特点。
●理解它们的区别:包括成员变量、方法实现、继承和实现方式。
●知道使用场景:描述接口和抽象类适用的不同编程场景。
更多推荐

所有评论(0)