Kotlin 对象类型
Kotlin 中的对象类型系统非常丰富,主要包括类和对象、数据类、密封类、枚举类等。以下是详细的分类和用法:
1. 类和对象
基本类定义
// 简单类
class Person {
var name: String = ""
var age: Int = 0
fun introduce() {
println("I'm $name, $age years old")
}
}
// 带主构造器的类
class Person(val name: String, var age: Int) {
// 属性已经在主构造器中声明
fun greet() = "Hello, I'm $name"
}
// 带初始化块的类
class Person(name: String, age: Int) {
val name: String
var age: Int
init {
this.name = name
this.age = age
println("Person created: $name")
}
}
构造器
// 主构造器 + 次构造器
class Person(val name: String, var age: Int) {
constructor(name: String) : this(name, 0) {
println("使用次构造器")
}
constructor() : this("Unknown", 0)
}
// 使用
val p1 = Person("Alice", 25) // 主构造器
val p2 = Person("Bob") // 次构造器
val p3 = Person() // 无参次构造器
属性和字段
class Person {
// 属性
var name: String = ""
// 计算属性(只读)
val isAdult: Boolean
get() = age >= 18
// 属性带自定义访问器
var age: Int = 0
set(value) {
if (value >= 0) {
field = value
} else {
println("年龄不能为负数")
}
}
get() {
println("读取年龄: $field")
return field
}
// 延迟初始化属性
lateinit var nickname: String
// 常量属性
companion object {
const val MAX_AGE = 150
}
}
2. 数据类 (Data Class)
专门用于存储数据的类,自动生成常用方法。
// 基本数据类
data class Person(
val name: String,
var age: Int,
val city: String = "Unknown"
)
// 使用
val person1 = Person("Alice", 25, "New York")
val person2 = Person("Alice", 25, "New York")
val person3 = person1.copy(age = 26) // 复制并修改
// 自动生成的方法
println(person1 == person2) // true - equals()
println(person1.hashCode()) // hashCode()
println(person1.toString()) // "Person(name=Alice, age=25, city=New York)"
println(person1.component1()) // name - 解构声明支持
// 解构声明
val (name, age, city) = person1
println("$name is $age years old from $city")
限制和注意事项
// 数据类必须满足的条件:
// 1. 主构造器至少有一个参数
// 2. 所有主构造器参数必须是 val 或 var
// 3. 不能是 abstract、open、sealed 或 inner
// 可以额外定义属性和方法
data class User(
val id: Int,
val name: String
) {
var isActive: Boolean = true // 不在 toString/equals/hashCode 中
fun displayInfo() = "[$id] $name"
}
// 通过 componentN 方法支持解构
operator fun User.component3() = isActive
3. 密封类 (Sealed Class)
用于表示受限的类层次结构,类似枚举的扩展。
// 定义密封类
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}
// 使用(when 表达式是完备的)
fun handleResult(result: Result<String>) {
when (result) {
is Result.Success -> println("成功: ${result.data}")
is Result.Error -> println("错误: ${result.exception}")
Result.Loading -> println("加载中...")
// 不需要 else 分支,因为所有情况都已覆盖
}
}
// 嵌套密封类
sealed class Expression {
data class Number(val value: Int) : Expression()
data class Sum(val left: Expression, val right: Expression) : Expression()
data class Multiply(val left: Expression, val right: Expression) : Expression()
}
// 递归计算表达式
fun eval(expr: Expression): Int = when (expr) {
is Expression.Number -> expr.value
is Expression.Sum -> eval(expr.left) + eval(expr.right)
is Expression.Multiply -> eval(expr.left) * eval(expr.right)
}
4. 枚举类 (Enum Class)
// 基本枚举
enum class Color {
RED, GREEN, BLUE
}
// 带属性的枚举
enum class Direction(val degrees: Int) {
NORTH(0),
EAST(90),
SOUTH(180),
WEST(270);
fun opposite(): Direction = when (this) {
NORTH -> SOUTH
EAST -> WEST
SOUTH -> NORTH
WEST -> EAST
}
}
// 枚举实现接口
enum class LogLevel : Comparable<LogLevel> {
DEBUG, INFO, WARN, ERROR;
override fun compareTo(other: LogLevel): Int {
return this.ordinal - other.ordinal
}
}
// 使用
val color = Color.RED
println(color.name) // "RED"
println(color.ordinal) // 0
// 遍历枚举
for (direction in Direction.values()) {
println("${direction.name}: ${direction.degrees}°")
}
// 根据名称获取枚举
val blue = Color.valueOf("BLUE")
val maybeColor = enumValueOfOrNull<Color>("PURPLE") // Kotlin 1.9+
5. 对象表达式和对象声明
对象表达式(匿名对象)
// 创建匿名对象
val clickListener = object : ClickListener {
override fun onClick() {
println("Clicked!")
}
fun extraMethod() {
println("额外方法")
}
}
// 继承多个类型
val multiInterface = object : ClickListener, HoverListener {
override fun onClick() { /* ... */ }
override fun onHover() { /* ... */ }
}
// 不继承任何类的对象
val adHocObject = object {
val x = 10
val y = 20
fun sum() = x + y
}
println(adHocObject.sum()) // 30
对象声明(单例)
// 对象声明(单例)
object Singleton {
private var counter = 0
fun increment() {
counter++
}
fun getCount() = counter
// 初始化代码
init {
println("Singleton initialized")
}
}
// 使用
Singleton.increment()
println(Singleton.getCount()) // 1
// 伴生对象
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
const val VERSION = "1.0"
}
}
// 使用伴生对象
val instance = MyClass.create()
val version = MyClass.VERSION
// 匿名伴生对象
class AnotherClass {
companion object {
@JvmStatic // 在Java中作为静态方法访问
fun staticMethod() {
println("静态方法")
}
}
}
6. 嵌套类和内部类
class Outer {
private val outerProperty = "Outer"
// 嵌套类(静态内部类)
class Nested {
fun foo() {
// 不能访问 outerProperty
println("Nested class")
}
}
// 内部类(持有外部类引用)
inner class Inner {
fun bar() {
println("Inner class accessing: $outerProperty")
}
}
// 局部类
fun createLocalClass(): Comparable<String> {
class LocalClass(val value: String) : Comparable<String> {
override fun compareTo(other: String): Int {
return value.compareTo(other)
}
}
return LocalClass("test")
}
}
// 使用
val nested = Outer.Nested() // 不需要 Outer 实例
val outer = Outer()
val inner = outer.Inner() // 需要 Outer 实例
7. 抽象类和接口
// 接口
interface Drawable {
fun draw() // 抽象方法
// 默认实现
fun prepare() {
println("准备绘制")
}
// 属性
val color: String
}
// 抽象类
abstract class Shape(val name: String) : Drawable {
abstract val area: Double
// 具体方法
fun displayInfo() {
println("形状: $name, 面积: $area")
}
}
// 实现
class Circle(val radius: Double) : Shape("圆形") {
override val area: Double
get() = Math.PI * radius * radius
override val color: String = "Red"
override fun draw() {
println("绘制圆形,半径: $radius")
}
// 重写默认实现
override fun prepare() {
super.prepare()
println("特别准备圆形绘制")
}
}
8. 泛型类和类型参数
// 泛型类
class Box<T>(var content: T) {
fun getContent(): T = content
fun setContent(newContent: T) {
content = newContent
}
// 泛型方法
fun <R> transform(transformer: (T) -> R): Box<R> {
return Box(transformer(content))
}
}
// 使用
val intBox = Box(42)
val stringBox = Box("Hello")
// 类型投影(协变/逆变)
interface Source<out T> { // 协变 - 只能作为返回值
fun next(): T
}
interface Consumer<in T> { // 逆变 - 只能作为参数
fun consume(item: T)
}
// 星投影
fun printItems(items: List<*>) {
for (item in items) {
println(item)
}
}
9. 内联类 (Inline Class)
值类型的包装类,运行时会被优化掉。
// 内联类(Kotlin 1.3+,1.5+ 稳定)
@JvmInline
value class Password(val value: String) {
// 可以定义方法和属性
val length: Int
get() = value.length
fun isValid(): Boolean = value.length >= 8
init {
require(value.length >= 8) { "密码必须至少8位" }
}
}
// 使用 - 运行时只有 String,没有 Password 对象
val password = Password("secret123")
println(password.length) // 8
// 支持解构
val (rawPassword) = password
// 内联类作为类型别名,但有更强的类型安全
typealias EmailAlias = String
@JvmInline value class Email(val value: String)
fun sendEmail(email: Email) { /* ... */ }
// sendEmail("test@example.com") // 编译错误 - 类型不匹配
sendEmail(Email("test@example.com")) // 正确
10. 类型检查和转换
// 类型检查
val obj: Any = "Hello"
if (obj is String) {
println(obj.length) // 智能转换
}
// 安全转换
val str: String? = obj as? String // 失败返回 null
// 类型擦除和具体化类型参数(内联函数)
inline fun <reified T> isInstance(obj: Any): Boolean {
return obj is T
}
// 使用
println(isInstance<String>("test")) // true
println(isInstance<Int>("test")) // false
最佳实践
- 优先使用数据类存储数据
- 使用密封类表达受限的类层次
- 考虑内联类包装基本类型以增加类型安全
- 伴生对象替代 Java 的静态方法
- 对象声明实现单例模式
- 合理使用嵌套/内部类,避免不必要的内存泄漏
Kotlin 的对象类型系统提供了强大而灵活的工具,可以帮助你编写更安全、更表达力的代码。