编程Kotlin开发者

Kotlin中普通类、抽象类和接口有什么区别,何时应用什么工具?

用 Hintsage AI 助手通过面试

回答。

问题的历史:

Kotlin结合了Java的优点和JVM的函数继承。普通类作为标准结构声明,抽象类允许创建未完全定义的模板并提供默认实现,而接口则支持无状态的多重行为继承。

问题:

在类、抽象类和接口之间的正确选择决定了应用程序的架构、代码的粒度及其可扩展性。错误的继承会导致测试和今后变更的复杂性。

解决方案:

在Kotlin中:

  • 普通类:定义结构和行为。可以通过声明open进行继承。
  • 抽象类:无法直接创建。可以包含实现和/或抽象(没有主体)方法。
  • 接口:隐式开放,实施合同,允许方法的实现,但不存储状态(仅属性,无后备字段)。

代码示例:

interface Drawable { fun draw() } abstract class Shape(var color: String) : Drawable { abstract fun calcArea(): Double override fun draw() = println("Shape drawn") } class Circle(color: String, val radius: Double) : Shape(color) { override fun calcArea() = Math.PI * radius * radius }

关键特性:

  • 接口允许多重实现,抽象类仅允许单一实现
  • 接口不能存储状态,抽象类可以
  • 抽象类可以实现部分接口并包含自己的通用逻辑

误导性问题。

接口可以包含带有后备字段的属性吗?

不可以,它们只能定义属性的签名,而不能存储数据—没有后备字段的属性。

可以从多个类继承吗?

不可以,Kotlin仅支持类的单一继承,但支持接口的多重实现。

接口可以声明构造函数吗?

不可以,接口不支持构造函数,因为它不存储状态—仅行为合同。

常见错误和反模式

  • 在没有必要的情况下使用abstract class代替interface
  • 在interface中存储状态(不可能,但在设计时犯错)
  • 设计类的层次结构,导致扩展困难

生活中的例子

消极案例

在应用程序中,将所有公共功能移到抽象类中,即使没有内部逻辑或状态,需求只是一个公共合同。

优点:

  • 逻辑的单一更改点

缺点:

  • 多重继承的问题,与其他结构集成困难

积极案例

仅将必要的合同提取到接口中,抽象类限制为需要实现的公共属性和方法。

优点:

  • 灵活扩展、模块化、干净的合同

缺点:

  • 需要在早期阶段进行设计