欢迎光临
我们一直在努力

新Java基础(二十三):抽象类

在 Java 面向对象的学习中,抽象类是继封装、继承、多态之后的又一核心知识点,也是实现代码抽象和复用的重要手段,同时还是面试中的高频考点。本文将从抽象类的基本概念、定义语法、核心特性、使用场景到与接口的区别,全方位拆解 Java 抽象类,帮你彻底吃透这一知识点。

一、什么是抽象类?为什么需要抽象类?

在面向对象的设计中,我们会遇到这样一种情况:某个父类只定义了子类共同的行为特征,却无法具体实现该行为,因为不同子类的实现方式各不相同。

假设你的公司要进行招聘,招聘2名产品经理,10名程序员,现在让你和小A设计这个网站让报名人员填写基本信息。大概有两种设计方式—-。

小A的设计方法:

0

但是我们发现这两个页面基本上内容是相同的,于是你的设计方法是这样的:

0

我们将一些相同的信息都提取到一起我们把这个过程叫做—-抽象

抽象类的本质:是一种被抽象化的父类,是对多个具有共同特征的子类的抽象描述,它不能被实例化,只能作为子类的父类被继承,核心作用是规范子类的行为,同时实现代码的复用。

二、抽象类的定义语法

1. 抽象类的定义

使用abstract关键字修饰的类,就是抽象类,语法格式:

// 抽象类的定义
public abstract class 类名 {
// 类的成员:属性、普通方法、抽象方法等
}

2. 抽象方法的定义

使用abstract关键字修饰,只有方法声明,没有方法体(无{})的方法,就是抽象方法,语法格式:

// 抽象方法的定义,无方法体,以分号结尾
public abstract 返回值类型 方法名(参数列表);

3. 完整示例

以Animal抽象类为例,定义抽象方法eat()和普通方法breathe()(所有动物呼吸方式可统一实现):

// 抽象父类:Animal
public abstract class Animal {
// 普通属性
public String name;
// 普通方法:可直接实现,子类继承复用
public void breathe() {
System.out.println(name + "在呼吸");
}
// 抽象方法:只声明,由子类实现
public abstract void eat();
}

4. 抽象类的子类实现

抽象类必须被子类继承,子类需重写抽象类中所有的抽象方法(除非子类也是抽象类),否则编译报错。

// 子类Cat继承抽象类Animal
public class Cat extends Animal {
// 重写抽象方法eat(),实现具体逻辑
@Override
public void eat() {
name = "小猫";
System.out.println(name + "吃小鱼干");
}
}

// 子类Dog继承抽象类Animal
public class Dog extends Animal {
@Override
public void eat() {
name = "小狗";
System.out.println(name + "啃骨头");
}
}

5. 测试类

抽象类不能实例化(new Animal()会编译报错),但可以声明抽象类的引用,指向子类的实例(多态特性):

public class TestAnimal {
public static void main(String[] args) {
// 抽象类不能实例化
// Animal animal = new Animal(); // 编译报错

// 多态:抽象类引用指向子类实例
Animal cat = new Cat();
cat.eat(); // 输出:小猫吃小鱼干
cat.breathe(); // 输出:小猫在呼吸

Animal dog = new Dog();
dog.eat(); // 输出:小狗啃骨头
dog.breathe(); // 输出:小狗在呼吸
}
}

三、抽象类的核心特性

抽象类是特殊的类,既拥有普通类的特性,又有自身的特殊规则,这是学习的重点,也是易混点,核心特性总结如下:

1. 抽象类不能被实例化

这是抽象类最核心的特性,new 抽象类名()会直接编译报错,因为抽象类是 “不完整的类”,包含未实现的抽象方法,无法创建具体对象。

2. 抽象类可以包含多种成员

抽象类并非只有抽象方法,它可以包含普通类的所有成员:

  • 普通属性:如String name、int age;
  • 普通方法:有方法体,子类可直接继承复用,无需重写;
  • 抽象方法:无方法体,要求子类必须重写(子类非抽象类时);
  • 构造方法:抽象类有构造方法,用于子类继承时初始化父类的属性,子类通过super()调用;
  • 静态成员:静态属性和静态方法,可通过抽象类名.静态成员直接调用。

示例:含构造方法的抽象类

public abstract class Animal {
public String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
public abstract void eat();
}

// 子类通过super调用父类构造方法
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void eat() {
System.out.println(name + "吃小鱼干");
}
}

// 测试
Animal cat = new Cat("橘猫");
cat.eat(); // 输出:橘猫吃小鱼干

3. 子类必须重写抽象类的所有抽象方法

如果子类不是抽象类,就必须重写抽象父类中所有的抽象方法,缺一不可,否则编译器会直接报错;若子类也是抽象类,则可以不重写,由该抽象子类的子类去完成重写。

4. 抽象类可以被继承,支持单继承

抽象类的继承规则与普通类一致,Java 中类只支持单继承,即一个抽象类只能有一个直接父类,同时抽象类也可以继承普通类或另一个抽象类。

5. abstract关键字的使用限制

abstract关键字不能与以下关键字同时使用,否则编译报错:

  • final:final 类不能被继承,而抽象类必须被继承,二者冲突;
  • private:private 方法无法被子类访问,而抽象方法要求子类重写,二者冲突;
  • static:static 方法属于类,不依赖对象,而抽象方法需要子类实现,属于对象层面,二者冲突;
  • native:native 方法由本地代码实现,抽象方法无实现,二者冲突。

四、抽象类的使用场景

抽象类的设计符合面向对象的 “里氏替换原则”和“开闭原则”,在实际开发中,以下场景优先使用抽象类:

1. 定义多个子类的共同行为规范

当多个子类具有相同的方法声明,但实现逻辑不同时,将共同方法声明为抽象方法,放在抽象父类中,规范子类的行为,保证代码的一致性。比如:图形类(Circle、Rectangle、Triangle)都有getArea()(求面积)方法,抽象父类Shape定义抽象方法getArea(),子类各自实现自身的面积计算逻辑。

2. 实现代码的复用

抽象类中可定义普通方法和属性,子类继承后可直接复用,无需重复编写,减少代码冗余。比如:所有手机(Phone)都有powerOn()(开机)、powerOff()(关机)的通用逻辑,放在抽象父类Phone中实现,子类(HuaWei、Apple、Xiaomi)只需重写call()(通话)等个性化方法。

3. 作为多态的父类,提高代码的扩展性

抽象类的引用可以指向任意子类的实例,结合多态特性,在方法传参时使用抽象类作为参数类型,可接收所有子类对象,无需为每个子类单独写方法,大大提高代码的扩展性和可维护性。

示例:多态提升扩展性

// 抽象类Animal
public abstract class Animal {
public abstract void eat();
}
// 子类Cat、Dog、Bird(略)

// 测试类:喂动物方法,参数为抽象类Animal
public class Test {
public static void feed(Animal animal) {
animal.eat();
}
public static void main(String[] args) {
feed(new Cat()); // 喂猫
feed(new Dog()); // 喂狗
feed(new Bird()); // 喂鸟
// 新增子类Tiger,无需修改feed方法,直接传入即可,符合开闭原则
feed(new Tiger());
}
}

五、抽象类与普通类的区别

很多初学者容易混淆抽象类和普通类,这里通过表格清晰对比二者的核心区别:

表格

特性抽象类普通类
关键字修饰 需用 abstract 修饰 无需 abstract 修饰
实例化 不能被实例化 可以被实例化(new)
抽象方法 可以包含抽象方法 不能包含抽象方法
子类要求 子类非抽象时必须重写所有抽象方法 子类可自由重写父类方法
设计目的 规范子类行为 + 代码复用 描述具体对象的属性和行为

六、抽象类与接口的区别(高频面试题)

抽象类和接口都是 Java 中实现抽象化的方式,二者在功能上有相似之处,也是面试中必考的对比题,核心区别如下(重点记忆):

表格

特性抽象类接口(Interface)
关键字 abstract class interface
继承方式 类单继承(extends) 类多实现(implements),接口多继承
成员组成 可包含普通属性、抽象方法、普通方法、构造方法、静态成员 JDK8 前:只有常量(public static final)和抽象方法;JDK8 后:新增默认方法、静态方法;JDK9 后:新增私有方法
方法修饰符 抽象方法默认 public,可省略;普通方法可任意修饰(除 private/final/static) 所有方法默认 public abstract(JDK8 前);默认方法为 public default,静态方法为 public static
属性修饰符 属性可任意修饰(public/private/protected 等) 属性默认 public static final,必须初始化
构造方法 有构造方法 无构造方法
设计理念 体现继承关系,是对 “类” 的抽象,注重代码复用和行为规范 体现实现关系,是对 “行为” 的抽象,注重解耦和多实现
使用场景 多个子类有共同的属性和方法,需要代码复用 多个不相关的类有共同的行为,需要统一规范,实现多态
赞(0)
未经允许不得转载:171主机测评 » 新Java基础(二十三):抽象类
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址