Java基础(十二):抽象类与接口详解
Java基础系列文章
Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建
Java基础(二):八种基本数据类型详解
Java基础(三):逻辑运算符详解
Java基础(四):位运算符详解
Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南
Java基础(六):数组全面解析
Java基础(七): 面向过程与面向对象、类与对象、成员变量与局部变量、值传递与引用传递、方法重载与方法重写
Java基础(八):封装、继承、多态与关键字this、super详解
Java基础(九):Object核心类深度剖析
Java基础(十):关键字static详解
Java基础(十一):关键字final详解
Java基础(十二):抽象类与接口详解
目录
- 引言
- 一、抽象类(Abstract Class)
- 1、基本概念
- 2、抽象类的特性
- 3、抽象类的使用
- 二、接口(Interface)
- 1、基本概念
- 2、接口的特性
- 3、接口的使用
- 三、抽象类 vs 接口
- 1、语法层面对比
- 2、设计理念对比
- 3、代码示例对比
- 四、Java 8+ 的新特性对设计的影响
引言
在Java面向对象编程中,抽象类(Abstract Class)
和接口(Interface)
是两个非常重要的概念,它们都是实现多态和代码抽象
的重要机制。虽然Java 8之后接口的功能得到了极大增强,但抽象类和接口仍然有着本质的区别和各自适用的场景。
一、抽象类(Abstract Class)
1、基本概念
- 抽象类是一种
不能被实例化
的类,它通常作为其他类的基类(父类),用来定义一些通用的属性和行为
- 抽象类的主要目的是为子类提供一个公共的模板或部分实现,同时强制子类去实现某些特定的方法(即抽象方法)
- 要定义一个抽象类,需要使用关键字
abstract
修饰类
public abstract class Animal {// 可以有字段属性protected String name;// 可以有构造方法(但不能直接实例化)public Animal(String name) {this.name = name;}// 具体方法:有实现public void sleep() {System.out.println("The animal is sleeping");}// 抽象方法:只有声明,没有实现,必须使用 abstract关键字修饰public abstract void makeSound();
}
2、抽象类的特性
不能实例化
:无法创建抽象类的对象- 可以包含
抽象方法
和具体方法(包括静态方法)
:抽象方法没有实现,具体方法有实现 - 可以包含
实例变量
、静态变量
- 可以有
构造方法
:虽然不能直接实例化,但子类有默认的super()
或手动的super(实参列表)
- 子类继承抽象类后,
必须实现所有的抽象方法
(除非子类也是抽象类) 单继承限制
:一个类只能继承一个抽象类
3、抽象类的使用
// 子类继承抽象类
public class Dog extends Animal {public Dog(String name) {super(name);}@Overridepublic void makeSound() {System.out.println("Woof! Woof!");}
}// 使用
public class Main {public static void main(String[] args) {// Animal animal = new Animal("Generic"); // 错误!不能实例化抽象类Animal myDog = new Dog("Buddy");myDog.makeSound(); // 输出: Woof! Woof!myDog.sleep(); // 输出: The animal is sleeping}
}
二、接口(Interface)
1、基本概念
- 接口是一种完全抽象的引用类型,它定义了一组方法规范而不提供实现(Java 8 之前),也不能包含成员变量(除了常量)
- 接口的主要目的是定义一组规范或契约,让不同的类去实现这些规范,从而实现多态和解耦
- 使用关键字
interface
定义接口
public interface Swimmable {// 常量 默认是 public static finalint MAX_SPEED = 120;// 抽象方法 默认是 public abstractvoid swim();// Java 8+ 默认方法default void floatOnWater() {System.out.println("Floating on water");}// Java 8+ 静态方法static boolean canSwim(Object obj) {return obj instanceof Swimmable;}// Java 9+ 私有方法private void secretSwimTechnique() {System.out.println("Secret technique");}
}
2、接口的特性
Java 7 及以前
:只能包含抽象方法
和常量
- 公共的静态的常量:其中
public static final
可以省略 - 公共的抽象的方法:其中
public abstract
可以省略
- 公共的静态的常量:其中
Java 8
:引入了默认方法
(default methods)和静态方法
- 公共的默认的方法:其中
public
可以省略,但default
不能省略 - 公共的静态的方法:其中
public
可以省略,但static
不能省略 - 使用
default
关键字可以为接口提供默认实现,这样实现类可以选择是否重写该方法 - 接口中可以定义静态方法,并通过接口名直接调用
- 公共的默认的方法:其中
Java 9
:引入了私有方法
(private methods)- 接口中可以定义私有方法,用于在接口内部复用代码逻辑
没有构造方法
:不能实例化多实现
:一个类可以实现多个接口
3、接口的使用
public class Duck extends Animal implements Swimmable, Flyable {public Duck(String name) {super(name);}// 实现抽象类Animal中抽象方法@Overridepublic void makeSound() {System.out.println("Quack! Quack!");}// 实现接口Swimmable中抽象方法@Overridepublic void swim() {System.out.println("Duck is swimming");}// 实现接口Flyable中抽象方法@Overridepublic void fly() {System.out.println("Duck is flying");}
}// 使用
public class Main {public static void main(String[] args) {Duck duck = new Duck("Donald");duck.swim(); // 调用实现的接口方法 输出: Duck is swimmingduck.floatOnWater(); // 调用接口的默认方法 输出: Floating on waterSwimmable.canSwim(duck); // 调用接口的静态方法 返回: true}
}
三、抽象类 vs 接口
1、语法层面对比
特性 | 抽象类 | 接口 |
---|---|---|
实例化 | 不能 | 不能 |
方法类型 | 抽象方法和具体方法 | 抽象方法、默认方法、静态方法、私有方法 |
字段 | 可以有各种字段 | 只能有静态常量 |
构造方法 | 有 | 无 |
继承性 | 单继承 | 多实现 |
访问修饰符 | 各种修饰符 | 默认 public |
2、设计理念对比
抽象类
表示"是一个"的关系,用于定义相关对象的基本共性
。例如:Dog是一种Animal共享代码
:多个相关类需要共享相同的代码和字段扩展基类功能
:需要定义非静态、非final的字段或非public方法定义模板
:提供模板方法模式的基础实现
接口
表示"具有能力"的关系,用于定义对象的特定能力
。例如:Duck具有Swimmable和Flyable的能力定义契约
:定义类必须实现的行为,而不关心如何实现多重能力
:一个类需要具备多种不相关的能力解耦
:实现与定义分离,提高代码灵活性
3、代码示例对比
// 抽象类示例:图形类层次结构
public abstract class Shape {protected String color;public Shape(String color) {this.color = color;}public abstract double area();public abstract double perimeter();public String getColor() {return color;}
}public class Circle extends Shape {private double radius;public Circle(String color, double radius) {super(color);this.radius = radius;}@Overridepublic double area() {return Math.PI * radius * radius;}@Overridepublic double perimeter() {return 2 * Math.PI * radius;}
}// 接口示例:多能力组合
public interface Drawable {void draw();
}public interface Resizable {void resize(double factor);
}public class ResizableCircle extends Circle implements Drawable, Resizable {public ResizableCircle(String color, double radius) {super(color, radius);}@Overridepublic void draw() {System.out.println("Drawing a circle with color: " + getColor());}@Overridepublic void resize(double factor) {// 调整大小的实现}
}
四、Java 8+ 的新特性对设计的影响
Java 8 的默认方法使接口能够向后兼容地添加新功能,减少了破坏性变更
public interface Vehicle {void start();// 新添加的默认方法,不影响已有实现default void stop() {System.out.println("Vehicle stopped");}static void describe() {System.out.println("This is a vehicle interface");}
}
但是,这也带来了"多重继承"的复杂性,当多个接口有相同签名的默认方法
时:会出现冲突
public interface A {default void hello() {System.out.println("Hello from A");}
}public interface B {default void hello() {System.out.println("Hello from B");}
}public class C implements A, B {// 必须重写 hello() 方法解决冲突@Overridepublic void hello() {A.super.hello(); // 显式选择调用 A 的实现}
}