首页 / Android 入门教程 / 类与对象

Android 入门教程

类与对象

本教程共 100 篇 · 第 13 篇 · 更新于 2026-07-28 · 约 8 分钟阅读

AndroidAndroid 入门教程Kotlin类与对象构造函数继承抽象类接口

13. 类与对象

本节目标:学会用 Kotlin 定义类、写构造函数、用属性、做继承、实现接口和抽象类,搞懂 Kotlin 面向对象跟 Java 的区别。

定义类

class Person {
    var name: String = ""
    var age: Int = 0
}

Kotlin 类默认是 final 的(不能被继承),要能继承得加 open

open class Animal
class Dog : Animal()        // 继承要加 (),调用父类构造

主构造函数

Kotlin 把构造函数写在类名后面,叫主构造函数

class Person(val name: String, var age: Int)

参数加 val/var 就成了类的属性,自动生成 getter(var 还有 setter)。没加 val/var 只是构造参数,不是属性。

val p = Person("张三", 18)
println(p.name)     // 张三
p.age = 19          // var 可改
// p.name = "李四"  // val 只读,报错
Tip
  • 这一行代码相当于 Java 几十行:字段、构造函数、getter、setter。Kotlin 简洁的典型。

init 块

主构造函数不能有代码体,初始化逻辑放 init 块:

class User(val name: String, val age: Int) {
    init {
        require(age >= 0) { "年龄不能为负" }
        println("创建用户:$name")
    }
}

属性初始化和 init 块按出现顺序执行。可以有多个 init 块。

次构造函数

constructor 关键字,必须委托给主构造函数:

class User(val name: String, val age: Int) {
    var email: String = ""

    // 次构造函数,通过 this 委托主构造
    constructor(name: String) : this(name, 0)

    constructor(name: String, age: Int, email: String) : this(name, age) {
        this.email = email
    }
}
Note
  • 能用默认参数搞定的就别写次构造函数。Kotlin 鼓励用主构造 + 默认参数,少写一堆重载。

属性

class Circle {
    var radius: Double = 1.0
        set(value) {
            field = value             // field 是幕后字段
            recalculate()
        }

    val area: Double                  // 只读属性,自定义 getter
        get() = Math.PI * radius * radius

    private fun recalculate() { /* ... */ }
}
  • field 是 Kotlin 给的幕后字段标识符,只在 getter/setter 内部用。
  • 自定义 getter 的属性可以没有幕后字段。

继承

open class Animal(val name: String) {
    open fun sound() {
        println("$name 发出声音")
    }
}

class Dog(name: String) : Animal(name) {
    override fun sound() {            // 重写要 override
        println("$name 汪汪叫")
    }
}

要点:

  • 父类要 open 才能被继承。
  • 要重写的方法也要 open,子类用 override
  • override 的方法默认还能被进一步重写,想锁住加 final override
  • 调用父类实现用 super

抽象类

abstract class Shape {
    abstract fun area(): Double          // 抽象方法,无实现
    fun describe() = "面积是 ${area()}"  // 普通方法
}

class Circle(val radius: Double) : Shape() {
    override fun area() = Math.PI * radius * radius
}

抽象类不能实例化,抽象方法子类必须实现。抽象类天然是 open 的,不用加。

接口

Kotlin 接口比 Java 8 的接口更强,能有默认实现:

interface Clickable {
    fun click()                          // 抽象方法
    fun showOff() = println("我能被点击")  // 默认实现
}

class Button : Clickable {
    override fun click() {
        println("按钮被点击")
    }
    // showOff 不重写就用默认实现
}

实现多个接口

接口可以多实现,类继承只能单继承:

interface Focusable {
    fun focus()
    fun showOff() = println("我能获得焦点")
}

class Button : Clickable, Focusable {
    override fun click() { /* ... */ }
    override fun focus() { /* ... */ }

    // 两个接口都有 showOff,必须重写消歧义
    override fun showOff() {
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}
Note
  • 接口里的属性不能有幕后字段(不能存状态),只能是抽象的或有 getter 的。需要状态用抽象类。

interface vs abstract 怎么选

  • 接口:定义「能力」,类可以多实现。比如 ClickableDrawableComparable
  • 抽象类:定义「是什么」,共享代码和状态。比如 BaseActivityBaseViewModel

Android 里常见模式:抽象类做基类(共享逻辑),接口做能力契约。

可见性修饰符

Kotlin 四种可见性:

修饰符含义
public(默认)所有地方可见
private同一文件内可见(顶层)或同一类内(成员)
internal同一模块内可见
protected同一类及子类可见(不能用于顶层声明)
Tip
  • internal 是 Kotlin 特有的,模块内可见。Android 多模块项目里很有用,能控制 API 不暴露给其他模块。

object:单例

Kotlin 用 object 一行声明单例:

object AppConfig {
    val version = "1.0"
    fun init() { /* ... */ }
}

// 用法
AppConfig.init()
println(AppConfig.version)

底层编译成饿汉式单例,线程安全。比 Java 手写单例简洁太多。

伴生对象

Kotlin 没有 static 关键字。类级别的常量和工厂方法放在伴生对象(companion object)里:

class User(val name: String) {
    companion object {
        const val DEFAULT_NAME = "匿名"
        fun create(): User = User(DEFAULT_NAME)
    }
}

// 用法
User.DEFAULT_NAME
User.create()

const val 是编译期常量,比普通 val 更高效。伴生对象里能实现接口、做工厂。

Android 实战示例

// 抽象 Activity 基类
abstract class BaseActivity : ComponentActivity() {
    protected abstract val layoutRes: Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupContent()
    }

    protected abstract fun setupContent()
}

// 接口定义能力
interface Refreshable {
    fun refresh()
}

// 数据模型
class UserSession(val userId: String) {
    var token: String? = null
        private set

    companion object {
        const val KEY_USER_ID = "user_id"
    }
}

小结

主构造写在类名后,参数加 val/var 成属性,初始化放 init 块。继承要 open,重写要 override。抽象类共享代码,接口定义能力可多实现。object 做单例,伴生对象放类级常量和工厂。可见性多了 internal。下一节学数据类与密封类。