1. 什么是抽象类?
抽象类是一个包含抽象方法和普通方法的类,它用来定义一组具有共同特征的类的模板。抽象类本身不能被实例化,但它可以通过子类继承并实现抽象方法,从而完成具体的功能。
1.1 抽象类的核心特点
- 不能实例化:抽象类是为了让子类继承用的,不能直接创建抽象类的对象。
- 可以有抽象方法和普通方法:
- 抽象方法:方法没有方法体(
{}
),只定义了方法签名(即方法名称、参数和返回值)。 - 普通方法:与普通类的普通方法一样,可以有方法体。
- 抽象方法:方法没有方法体(
- 可以有构造方法:抽象类虽然不能实例化,但它可以有构造方法供子类调用,用于初始化父类部分的成员变量。
- 可以有成员变量:抽象类可以定义变量,这些变量可以被子类继承和使用。
- 必须被子类继承:子类如果继承了抽象类,必须实现其所有抽象方法;否则,子类也必须是抽象类。
- 可以包含静态方法和静态变量:这些方法和变量属于类本身,而不是某个具体的实例。
1.2 抽象类的用途
- 规范化代码:定义子类的共同行为规范(抽象方法),同时可以提供部分实现。
- 代码复用:将通用的代码放在抽象类中,所有子类都可以继承,避免代码重复。
- 多态支持:通过父类引用调用子类的方法,增强代码的灵活性。
2. 抽象类的定义和语法
下面是一个完整的抽象类定义的示例:
// 抽象类
abstract class Animal {
// 普通成员变量
String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 抽象方法(没有方法体)
abstract void makeSound();
// 普通方法(有方法体)
void eat() {
System.out.println(name + " is eating.");
}
}
// 继承抽象类
class Dog extends Animal {
public Dog(String name) {
super(name); // 调用父类构造方法
}
// 实现抽象方法
@Override
void makeSound() {
System.out.println(name + " says: Woof!");
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
// 实现抽象方法
@Override
void makeSound() {
System.out.println(name + " says: Meow!");
}
}
// 测试抽象类
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Buddy");
dog.makeSound(); // 输出:Buddy says: Woof!
dog.eat(); // 输出:Buddy is eating.
Animal cat = new Cat("Kitty");
cat.makeSound(); // 输出:Kitty says: Meow!
cat.eat(); // 输出:Kitty is eating.
}
}
3. 抽象类的组成
组成部分 | 说明 |
---|---|
抽象方法 | 没有方法体,使用 abstract 关键字修饰,强制子类实现。 |
普通方法 | 有方法体,子类可以直接继承使用,也可以选择重写。 |
成员变量 | 抽象类可以包含成员变量,子类可以继承和使用。 |
构造方法 | 抽象类可以有构造方法,用于子类调用父类的初始化代码。 |
静态方法 | 静态方法属于类本身,可以直接通过类名调用,而无需实例化。 |
静态变量 | 抽象类可以定义静态变量,供所有子类共享。 |
访问修饰符 | 抽象类本身可以有 public 、protected 或默认修饰符,方法和变量可以有 private 、protected 或 public 修饰符。 |
4. 抽象类的细节与注意事项
4.1 抽象方法的规则
- 抽象类中可以有零个或多个抽象方法。一个没有抽象方法的抽象类是合法的,但它通常仅用于不允许直接实例化的情况。
- 子类必须实现所有抽象方法,否则子类也必须声明为抽象类。
示例:
abstract class Shape {
abstract double calculateArea(); // 抽象方法
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
double calculateArea() {
return Math.PI * radius * radius; // 实现抽象方法
}
}
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
double calculateArea() {
return width * height; // 实现抽象方法
}
}
// 测试
public class Main {
public static void main(String[] args) {
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
System.out.println("Circle Area: " + circle.calculateArea()); // 输出:Circle Area: 78.53981633974483
System.out.println("Rectangle Area: " + rectangle.calculateArea()); // 输出:Rectangle Area: 24.0
}
}
4.2 抽象类的限制
- 不能用
final
修饰抽象类:
如果一个类被声明为final
,它不能被继承,而抽象类的存在是为了被继承,因此两者冲突。 - 不能直接实例化:
Shape shape = new Shape(); // 错误!抽象类不能被实例化
4.3 抽象类和普通类的区别
比较点 | 抽象类 | 普通类 |
---|---|---|
是否可以实例化 | 不能实例化 | 可以实例化 |
是否有抽象方法 | 可以包含抽象方法 | 不可以包含抽象方法 |
是否有构造方法 | 可以有构造方法(供子类调用) | 可以有构造方法 |
继承目的 | 用于定义模板和强制子类实现规范 | 用于实现具体功能 |
5. 抽象类与接口的比较
Java 中的抽象类和接口有一些类似的功能,但它们适用于不同的场景。
特性 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract | interface |
是否支持多继承 | 不支持多继承(一个类只能继承一个抽象类) | 支持多实现(一个类可以实现多个接口) |
是否可以有构造方法 | 可以有构造方法 | 不可以有构造方法 |
是否可以有普通变量 | 可以有普通变量 | 只能有 public static final 常量 |
是否可以有方法实现 | 可以有方法实现(普通方法) | Java 8 开始支持默认方法和静态方法 |
使用场景 | 描述类的本质(“is-a” 关系,例如“Dog is an Animal”) | 描述行为的能力(“can-do” 关系,例如“Bird can Fly”) |
示例:抽象类描述本质,接口描述能力
abstract class Animal {
abstract void makeSound();
}
interface Flyable {
void fly();
}
class Bird extends Animal implements Flyable {
@Override
void makeSound() {
System.out.println("Bird chirps");
}
@Override
public void fly() {
System.out.println("Bird is flying");
}
}
评论留言
欢迎您,!您可以在这里畅言您的的观点与见解!
0 条评论