14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)

作者:Android_小雨日期:2025/11/28

希望帮你在Kotlin进阶路上少走弯路,在技术上稳步提升。当然,由于个人知识储备有限,笔记中难免存在疏漏或表述不当的地方,也非常欢迎大家提出宝贵意见,一起交流进步。 —— Android_小雨

整体目录:Kotlin 进阶不迷路:41 个核心知识点,构建完整知识体系

一、前言

在面向对象编程(OOP)的世界里,我们经常会遇到一种情况:我们能够清晰地描述一类事物的共同特征,但对于某些具体的行为,却无法在父类中给出确切的定义。

1.1 抽象类的核心价值

抽象类(Abstract Class)的核心价值在于定义共性模板约束子类实现。 它像是一个半成品的蓝图,规定了建筑的基本结构(共性),但留下了某些具体的装修风格(个性)给子类去完成。

1.2 Kotlin 抽象类的设计初衷

Kotlin 设计抽象类的初衷,是在代码复用子类规范之间寻找平衡。

  • 复用:将通用的状态和逻辑提取到父类,避免重复代码。
  • 规范:通过抽象方法强制子类必须实现特定逻辑,保证业务流程的完整性。

1.3 本文核心内容预告

本文将带您深入 Kotlin 抽象类的世界,路线如下:

  • 基础定义:语法与混合成员结构。
  • 核心特性:不可实例化、构造函数支持与强制约束。
  • 继承实战:4 种实现抽象成员的高级技巧。
  • 实战场景:BaseActivity、业务模板与共性逻辑封装。

二、抽象类基础:定义与语法规范

2.1 基本语法

在 Kotlin 中,使用 abstract 关键字来修饰一个类,使其成为抽象类。

1abstract class BaseTemplate {
2    // ...
3}
4
5

2.2 抽象成员

使用 abstract 修饰的属性或方法,称为抽象成员。它们没有具体的实现(没有方法体,也没有属性初始化器),仅定义了“签名”。

2.3 非抽象成员

抽象类中可以包含普通(非抽象)的成员。这些成员可以有具体的实现,供子类直接复用。这是抽象类区别于接口的重要特征之一。

2.4 基础示例(定义抽象基类)

让我们看一个包含所有成员类型的完整示例:

1abstract class Animal(
2    open val name: String // 构造函数中的属性
3) {
4    // 2.3 非抽象成员:有状态,有实现
5    val creationTime = System.currentTimeMillis()
6
7    fun sleep() {
8        println("$name 正在睡觉")
9    }
10
11    // 2.2 抽象成员:无状态,无实现,强制子类定义
12    abstract val species: String
13    abstract fun makeSound()
14
15    // open 成员:有实现,但允许子类重写
16    open fun move() {
17        println("移动中...")
18    }
19}
20
21

三、抽象类的核心特性

根据 Kotlin 官方文档,抽象类有以下核心法则:

3.1 不可直接实例化

抽象类是“半成品”,因此你不能直接创建抽象类的实例。

1fun main() {
2    //  编译错误:Cannot create an instance of an abstract class
3    // val animal = Animal("Test")
4}
5
6

3.2 子类的强制约束

如果一个非抽象类继承了抽象类,它必须实现(Override)父类中所有的抽象成员。这是抽象类的核心契约精神。

3.3 支持构造函数

与接口不同,抽象类可以拥有构造函数(主构造函数或次构造函数)和 init 代码块,用于初始化抽象类中的状态(State)。

3.4 兼容继承规则

  • 抽象成员:隐含 open,必须被重写。
  • 非抽象成员:默认为 final(不可重写)。如果希望子类能重写非抽象成员,必须显式加上 open 关键字。

四、抽象类的继承与实现步骤

4.1 子类继承抽象类

使用冒号 : 进行继承,并必须调用父类的构造函数。

4.2 实现抽象属性 / 方法

这是进阶的关键点。在 Kotlin 中,实现抽象成员有 4 种官方认可的合法方式

1abstract class Base {
2    abstract val size: Int
3}
4
5class Concrete : Base() {
6    // 方式 1:直接赋值(最常见,生成 backing field 占用内存)
7    override val size: Int = 100
8
9    // 方式 2:自定义 Getter(推荐用于计算属性,不占内存)
10    // override val size: Int get() = 100
11
12    // 方式 3:逻辑计算
13    // override val size: Int get() = if (System.currentTimeMillis() > 0) 100 else 0
14
15    // 方式 4:var + setter(少见但合法)
16    // override var size: Int = 100
17}
18
19

4.3 重写非抽象成员

子类可以重写父类中标记为 open 的非抽象成员,并通过 super 关键字调用父类逻辑。

4.4 完整实战示例

我们将 Shape 抽象类落地为具体的 Circle

1// 抽象父类
2abstract class Shape(val color: String) {
3    abstract fun calculateArea(): Double
4
5    open fun printInfo() {
6        println("I am a $color shape.")
7    }
8}
9
10// 子类实现
11class Circle(color: String, val radius: Double) : Shape(color) {
12    // 必须实现抽象方法
13    override fun calculateArea(): Double = Math.PI * radius * radius
14
15    // 选择性重写 open 方法
16    override fun printInfo() {
17        super.printInfo() // 复用父类逻辑
18        println("Type: Circle, Radius: $radius")
19    }
20}
21
22

五、抽象类的典型应用场景

5.1 框架基础模板 (Android BaseActivity)

利用抽象类统一生命周期管理和初始化流程,这是 Android 开发中最经典的应用。

1abstract class BaseActivity : AppCompatActivity() {
2
3    override fun onCreate(savedInstanceState: Bundle?) {
4        super.onCreate(savedInstanceState)
5        setContentView(getLayoutId()) // 模板逻辑:设置布局
6        initViews()                   // 模板逻辑:初始化视图
7        initData()                    // 模板逻辑:加载数据
8    }
9
10    // 强制子类提供布局 ID
11    abstract fun getLayoutId(): Int
12
13    // 强制子类实现初始化逻辑
14    abstract fun initViews()
15    abstract fun initData()
16}
17
18

5.2 业务规范定义 (支付策略)

强制子类实现核心业务逻辑,确保业务完整性。

1abstract class PaymentProcessor {
2    // 核心支付逻辑,强制子类实现(支付宝、微信、银行卡逻辑不同)
3    abstract fun pay(amount: Double)
4
5    // 公共逻辑:支付前检查(可复用,也可重写)
6    open fun checkRisk(): Boolean {
7        println("执行通用风控检查...")
8        return true
9    }
10}
11
12

5.3 共性逻辑封装 (Template Method 模式)

在 ViewModel 或 Presenter 层,封装数据加载的“骨架”。

1abstract class BaseViewModel {
2    // 模板方法:定义加载数据的标准流程
3    fun loadData() {
4        showLoading()
5        try {
6            val data = fetchData() // 具体获取数据的逻辑由子类决定
7            showSuccess(data)
8        } catch (e: Exception) {
9            showError(e)
10        }
11    }
12
13    abstract fun fetchData(): Any
14    // ... 省略 showLoading 等通用实现
15}
16
17

六、抽象类的使用边界与注意事项

6.1 与普通类的核心区别

特性普通类 (Class)抽象类 (Abstract Class)
实例化可以直接创建对象不可实例化
成员修饰默认为 final默认为 open (抽象成员),支持 abstract 修饰
用途具体业务实现继承体系的基石/模板

6.2 与接口的初步区分

这是架构选型时的关键决策点:

特性抽象类接口 (Interface)
状态 (State)支持(有 backing field)不支持(无状态)
构造函数支持不支持
多继承不支持(单继承)支持
设计意图Is-A (它是...)、模板复用Can-Do (它能...)、行为契约

6.3 避坑点 (常见编译错误)

错误信息原因与解法
Abstract member not implemented子类忘记实现抽象方法。解法:添加 override 实现。
Property must be initialized or be abstract属性没赋值也没加 abstract。解法:初始化或声明为 abstract。
This type is final试图继承普通类。解法:父类加 open 或 abstract。

七、总结与最佳实践

7.1 核心知识点回顾

  • 关键字abstract
  • 三大特征:不可实例化、包含抽象成员、强制子类实现。
  • 继承规则:单继承,抽象成员必须 override,非抽象成员需 open 才可 override。

7.2 适用场景

当多个类之间存在明显的家族相似性(Is-A 关系),且你需要复用代码(状态/具体方法)同时又需要强制约束某些行为时,抽象类是最佳选择。

7.3 实践建议

  • 多组合,少继承:抽象类虽好,但继承耦合度高。仅在确实需要模板复用时使用。
  • 命名规范:通常以 Base 开头(如 BaseActivity)或直接使用名词(如 Shape),清晰表达其作为基类的身份。

14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)》 是转载文章,点击查看原文


相关推荐


Mermaid: AI 时代画图的魔法工具
uzong2025/11/25

1. 掌握 Mermaid:用代码绘制专业图表,让技术表达更高效 随着工作年限增加,画图的需求日渐增多。而一张清晰的图表往往胜过千言万语。大模型(如 GPT、通义千问等)日益普及的今天,通过大模型自动生成 Mermaid 语法代码,再一键渲染成精美图表。 大大节省了日常工作效率,实现10倍效率提升。 2. 什么是 Mermaid? Mermaid 是一个基于 JavaScript 的图表绘制工具,它使用类似于 Markdown 的简单文本语法来创建各种图表。你只需要编写简单的代码,就能自动生成


Python编程实战:Python常用命令速查表(超全整理)
程序员爱钓鱼2025/11/24

在 Python 开发过程中,很多命令与工具操作很容易忘记。无论你是新手还是经验开发者,拥有一份随手可查的“命令速查表”都能显著提升开发效率。 本篇文章总结了 Python、pip、虚拟环境、包管理、文件操作、调试、格式化、性能测试、代码检查 等常用命令,是一份覆盖面非常全面的 Python 开发必备备忘录。 你可以将此文加入收藏夹或做成一页纸随身文档。 1. Python 命令速查 基础命令 用途命令查看 Python 版本pyth


盘点放弃Cursor期间发布的新特性,我再次心动了
小溪彼岸2025/11/22

前言 小伙伴们大家好,我是小溪,见字如面。想想退订Cursor已经三个多月了,退订期间基本上就没有打开过Cursor,一直处于在 Trae、Kiro、CodeBuddy、Qoder 等AI编辑器之间来回切换的状态,对市面上的这些已开启订阅收费的AI编辑器有过期待,更多的是体验过后的心碎,因为到目前为止没有一个AI编辑器赶超我曾经最喜欢的Cursor Tab的。今天无意间打开Cursor,发现Cursor已经更新到 2.0 版本了,想当初我使用的还是 0.49 版本,这个更新速度真是惊人,这次就来


CVPR 2024 目标检测!开放词汇
大模型实验室Lab4AI2025/11/20

CVPR 2024 目标检测!开放词汇 01 论文概述 论文名称:YOLO-World: Real-Time Open-Vocabulary Object Detection 会议名称:CVPR (2024) 👉一键直达论文 👉Lab4AI大模型实验室论文 🌟简介 在相当长的一段时间里,目标检测领域存在一个核心的权衡:要么选择像 YOLO 系列那样拥有极致速度但只能识别固定类别的“闭集”检测器,要么选择像 Grounding DINO 那样能够识别任意文本描述但速度较


软件苹果商城上架的流程与团队协作模式 一个项目从开发到发布的完整经历
aiopencode2025/11/19

在很多技术团队里,“软件苹果商城上架” 常常被安排在项目周期的末尾,甚至被视为上线前的最后一道关卡。 但经历过多次 iOS 上架之后,你会发现——这不是简单的“把 IPA 传上去”,而是一段涉及角色分工、工具链协同、发布审核管理的完整流程。 在这篇文章中,我将以一个真实团队的视角,讲述我们如何把一款跨平台 App 成功上架到苹果商城(App Store),重点分享工程侧如何配合产品、设计、测试等角色,在没有单一 Mac 依赖的情况下完成上架流程。 一、项目收尾阶段:上架并不是“最后一个动作”


Python 的内置函数 type
IMPYLH2025/11/17

Python 内建函数列表 > Python 的内置函数 type Python 的内置函数 type() 是一个非常重要的函数,它主要用于获取对象的类型信息。这个函数有两种主要用法: 单参数调用: 当传入一个参数时,type() 会返回该对象的类型(类)。返回的结果是一个类型对象,通常显示为 <class '类型名称'> 的格式。 示例: print(type(42)) # <class 'int'> print(type("hello")) # <class 's


Python 的内置函数 repr
IMPYLH2025/11/16

Python 内建函数列表 > Python 的内置函数 repr Python 的内置函数 repr() 是一个非常重要的对象字符串表示函数,其主要功能是返回一个对象的"官方"字符串表示形式(通常称为"representation")。这个字符串通常能够被 Python 解释器读取,并尽可能准确地重建该对象。 详细特性: 可重建性原则:repr() 返回的字符串理论上应该能够通过 eval() 函数重新构造出原对象与 str() 的区别:相比 str() 函数返回的可读性字符串,repr


Python 的内置函数 memoryview
IMPYLH2025/11/15

Python 内建函数列表 > Python 的内置函数 memoryview Python 的内置函数 memoryview 是一个用于访问其他二进制序列的内存视图对象,它允许在不复制底层数据的情况下直接操作原始数据。这在处理大型二进制数据(如音频、视频或图像文件)时特别有用,可以显著提升性能并减少内存消耗。 memoryview 的主要特点包括: 零拷贝访问:通过 memoryview 可以直接引用原始数据缓冲区,而不需要创建额外的数据副本。 支持缓冲区协议:可以操作任何支持 Py


Claude Code 深度解析:架构、工作原理与常见误解
袁洛施2025/11/14

Claude Code 深度解析:架构、工作原理与常见误解 本文档基于真实技术对话整理,深入剖析 Claude Code 的真实架构和工作原理 目录 核心问题关键发现架构解析常见误解技术细节 核心问题 Q1: Claude Code 是什么? 问题原文: “究竟什么是 Claude Code?Claude Code CLI 是个命令行终端,最终调用的还是 Anthropic Claude 大语言模型,比如 claude-sonnet-4-5-20250929


工业级部署指南:在西门子IOT2050(Debian 12)上搭建.NET 9.0环境与应用部署(进阶篇)
dephixf2025/11/13

在工业物联网(IIoT)场景中,实时监控设备状态和能源消耗是提升生产效率的核心需求。本文将详细介绍如何在 IOT2050 设备(搭载 Debian 12 系统)上,完成两大监控系统的部署:基于 Nginx 的设备监控管理 HTML 静态页面(负责可视化展示设备状态、工单数据)和Asp.net Core 能源监控系统(负责后端数据处理、能源趋势分析),实现从设备状态到能源消耗的全维度监控。 一、环境准备:IOT2050 基础配置 核心前提 IOT2050 设备已安装 Debian 12 操作

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2025 聚合阅读