抽象类和接口都是用来「定义规范、让子类去实现」的。

1. 抽象类

用 abstract 修饰的类。抽象类里可以有抽象方法(没有方法体)。

1
2
3
4
5
6
7
8
9
10
// 抽象类
public abstract class Shape {
// 抽象方法:只有声明,没有实现
abstract double area();

// 抽象类里也可以有普通方法
public void print() {
System.out.println("这是一个形状");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 子类继承抽象类,必须实现所有抽象方法
public class Circle extends Shape {
double r;

public Circle(double r) {
this.r = r;
}

@Override
double area() {
return Math.PI * r * r;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Rectangle extends Shape {
double width;
double height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

@Override
double area() {
return width * height;
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
// Shape s = new Shape(); // 编译报错:抽象类不能直接实例化

Shape c = new Circle(2);
System.out.println(c.area()); // 12.566370614359172

Shape r = new Rectangle(3, 4);
System.out.println(r.area()); // 12.0
}
}

要点:

  • 抽象类不能实例化(不能 new)
  • 子类继承抽象类,必须实现所有抽象方法,否则子类也得是抽象类

2. 接口

接口用 interface 定义,是一组方法的「契约」。类用 implements 实现接口。

1
2
3
4
// 接口:方法默认是 public abstract
public interface Flyable {
void fly();
}
1
2
3
public interface Swimmable {
void swim();
}
1
2
3
4
5
6
7
8
9
10
11
12
// 一个类可以实现多个接口
public class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("鸭子在飞");
}

@Override
public void swim() {
System.out.println("鸭子在游泳");
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.fly(); // 鸭子在飞
duck.swim(); // 鸭子在游泳

// 接口引用指向实现类对象
Flyable f = new Duck();
f.fly();
}
}

要点:

  • 接口方法默认 public abstract
  • 一个类可以实现多个接口(弥补单继承的限制)

3. 接口的默认方法和静态方法(JDK 8+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface Greeting {
// 抽象方法
void sayHi();

// 默认方法:有方法体,实现类可以不用重写
default void sayBye() {
System.out.println("再见");
}

// 静态方法:直接用接口名调用
static void info() {
System.out.println("这是一个问候接口");
}
}
1
2
3
4
5
6
public class Person implements Greeting {
@Override
public void sayHi() {
System.out.println("你好");
}
}
1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.sayHi(); // 你好
p.sayBye(); // 再见(继承的默认方法)

Greeting.info(); // 这是一个问候接口
}
}

4. 抽象类和接口的区别

对比项 抽象类 接口
继承/实现 单继承(extends) 可实现多个(implements)
方法 可以有抽象方法,也可以有普通方法 默认是抽象方法,JDK 8 起有默认/静态方法
字段 可以有实例字段 只能有常量(public static final)
语义 “是什么”(is-a) “能做什么”(has-a / can-do)

选择建议:

  • 表示「是什么」的继承关系,用抽象类(如 Dog 是 Animal)
  • 表示「具备什么能力」,用接口(如 Duck 能 Flyable、能 Swimmable)

小结

  • 抽象类:abstract 修饰,不能实例化,子类必须实现抽象方法
  • 接口:interface 定义规范,implements 实现,一个类可实现多个接口
  • 抽象类表示「是什么」,接口表示「能做什么」