抽象类和接口的区别

首先明白他们的使用场景?

  • 如果拥有一些方法,想要让它们有默认的具体实现,选择抽象类
  • 如果想要实现多重继承,Java中不支持多继承,但是一个类可以实现多个接口,选择接口
  • 如果有一些基本功能在不断发生变化,选择抽象类,如果使用接口,每次变更都需要去更改实现接口的所有类
抽象类 接口
它可以有默认的方法实现 接口是完全抽象的,不存在方法的实现
子类提供extends关键字来继承抽象类,并且子类不是抽象类的话,需要实现抽象类中声明的方法 子类使用关键字implements来实现接口,需要实现接口中声明的方法
抽象类中的成员变量可以是各种类型的 接口中的成员变量只能是public static final(隐式声明)类型(必须在声明时赋值)
抽象类中可以有静态代码块和静态方法 接口中不能含有静态代码块和静态方法(含有静态变量)
一个类只能继承一个抽象类 一个类可以实现多个接口
抽象方法中可以有public、protected、default这些修饰符 接口方法默认是public abstract

疑问:jdk1.8之后接口有默认的方法(default修饰),那么它也可以当作基本功能实现的方法呀?

我觉得最主要的原因是即使有默认方法,但是接口它没有字段(成员变量)和构造方法,这个默认方式实现的功能非常有限,因此代码复用性很差,并且抽象类它可以在不同的具体类之间共享代码。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
abstract class Animal {
protected String name;

public Animal(String name) {
this.name = name;
}

public abstract void makeSound();

public void eat() {
System.out.println(name + " is eating.");
}
}

class Dog extends Animal {
public Dog(String name) {
super(name);
}

@Override
public void makeSound() {
System.out.println(name + " is barking.");
}
}

class Cat extends Animal {
public Cat(String name) {
super(name);
}

@Override
public void makeSound() {
System.out.println(name + " is meowing.");
}
}

public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.makeSound(); // 输出:Buddy is barking.
dog.eat(); // 输出:Buddy is eating.

Cat cat = new Cat("Whiskers");
cat.makeSound(); // 输出:Whiskers is meowing.
cat.eat(); // 输出:Whiskers is eating.
}
}

Main 类中,我们分别创建了一个 Dog 对象和一个 Cat 对象,并分别调用了它们的方法。由于它们继承了抽象类 Animal,所以可以访问共享的字段和默认方法。