Skip to content

Kotlin 类(Classes):面向对象编程的基石 🏗️

引言:为什么需要类?

想象一下,你正在开发一个电商系统的后端服务。你需要处理用户信息、订单数据、商品详情等各种复杂的业务实体。如果没有类的概念,你可能需要用一堆零散的变量和函数来管理这些数据:

kotlin
// 没有类的混乱世界 😵‍💫
var userId1 = 1
var userEmail1 = "john@example.com"
var userName1 = "John"

var userId2 = 2
var userEmail2 = "jane@example.com"
var userName2 = "Jane"

// 当用户数量增加时,这种方式就崩溃了...

这就像试图用散落的积木搭建一座城堡——既混乱又容易出错。类(Class) 就是解决这个问题的利器,它让我们能够将相关的数据和行为封装在一起,创建出结构化、可复用的代码模块。

TIP

把类想象成一个"模板"或"蓝图"。就像建筑师的设计图纸一样,类定义了对象应该有什么属性和能做什么事情,而对象则是根据这个蓝图建造出来的具体实例。

核心概念:类的本质与价值

什么是类?

在 Kotlin 中,类(Class) 是一种用户定义的数据类型,它封装了:

  • 属性(Properties):描述对象的特征和状态
  • 方法(Methods):定义对象能执行的操作
  • 构造器(Constructors):创建对象实例的方式

类解决的核心问题

  1. 数据组织问题:将相关数据聚合在一起
  2. 代码复用问题:避免重复编写相似的代码
  3. 抽象建模问题:用代码表示现实世界的概念
  4. 维护性问题:让代码更易理解和修改

Kotlin 类的基础语法

1. 最简单的类声明

kotlin
class Customer

fun main() {
    val customer = Customer()                   
    println("创建了一个客户对象: $customer")
}

NOTE

注意 Kotlin 创建对象时不需要 new 关键字,这让代码更加简洁。Kotlin 会自动为没有显式构造器的类创建一个无参数的默认构造器。

2. 带属性的类(主构造器)

kotlin
class Contact(val id: Int, var email: String)   

fun main() {
    val contact = Contact(1, "mary@gmail.com")  
    
    println("联系人ID: ${contact.id}")           
    contact.email = "jane@gmail.com"
    println("更新后的邮箱: ${contact.email}")
}

IMPORTANT

  • val 声明的属性是不可变的(只读)
  • var 声明的属性是可变的(可读写)
  • 主构造器的参数会自动成为类的属性

SpringBoot 实战:用户管理系统

让我们通过一个真实的 SpringBoot 项目来看看类在服务端开发中的应用:

用户实体类设计

kotlin
// 传统 Java 风格的用户类(繁琐版本)
class UserTraditional {
    private var id: Long = 0
    private var username: String = ""
    private var email: String = ""
    private var createdAt: LocalDateTime = LocalDateTime.now()
    
    // 需要手动编写大量的 getter/setter
    fun getId(): Long = id
    fun setId(id: Long) { this.id = id }
    
    fun getUsername(): String = username
    fun setUsername(username: String) { this.username = username }
    
    // ... 更多 getter/setter
}
kotlin
// Kotlin 风格的用户类(优雅版本)
@Entity
@Table(name = "users")
data class User(                                    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,                               
    
    @Column(unique = true, nullable = false)
    val username: String,                           
    
    @Column(unique = true, nullable = false)
    var email: String,                              
    
    @Column(name = "created_at")
    val createdAt: LocalDateTime = LocalDateTime.now()
)

完整的用户服务示例

kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.web.bind.annotation.*
import org.springframework.stereotype.Service
import org.springframework.http.ResponseEntity
import javax.persistence.*
import java.time.LocalDateTime

// 用户实体类
@Entity
@Table(name = "users")
data class User(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,
    
    @Column(unique = true, nullable = false)
    val username: String,
    
    @Column(unique = true, nullable = false)
    var email: String,
    
    @Column(name = "created_at")
    val createdAt: LocalDateTime = LocalDateTime.now()
)

// 用户请求DTO类
data class CreateUserRequest(                       
    val username: String,
    val email: String
)

// 用户响应DTO类
data class UserResponse(                            
    val id: Long,
    val username: String,
    val email: String,
    val createdAt: LocalDateTime
) {
    companion object {
        fun from(user: User) = UserResponse(        
            id = user.id,
            username = user.username,
            email = user.email,
            createdAt = user.createdAt
        )
    }
}

// 数据访问层
interface UserRepository : JpaRepository<User, Long> {
    fun findByUsername(username: String): User?
    fun existsByEmail(email: String): Boolean
}

// 业务逻辑层
@Service
class UserService(private val userRepository: UserRepository) {
    
    fun createUser(request: CreateUserRequest): UserResponse {
        // 业务验证
        if (userRepository.existsByEmail(request.email)) {
            throw IllegalArgumentException("邮箱已存在")    
        }
        
        // 创建用户对象
        val user = User(                                    
            username = request.username,
            email = request.email
        )
        
        // 保存并返回
        val savedUser = userRepository.save(user)
        return UserResponse.from(savedUser)                 
    }
    
    fun getUserById(id: Long): UserResponse? {
        return userRepository.findById(id)
            .map { UserResponse.from(it) }                  
            .orElse(null)
    }
    
    fun updateUserEmail(id: Long, newEmail: String): UserResponse? {
        val user = userRepository.findById(id).orElse(null) ?: return null
        
        user.email = newEmail                               
        val updatedUser = userRepository.save(user)
        return UserResponse.from(updatedUser)
    }
}

// 控制器层
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
    
    @PostMapping
    fun createUser(@RequestBody request: CreateUserRequest): ResponseEntity<UserResponse> {
        return try {
            val user = userService.createUser(request)
            ResponseEntity.ok(user)
        } catch (e: IllegalArgumentException) {
            ResponseEntity.badRequest().build()             
        }
    }
    
    @GetMapping("/{id}")
    fun getUser(@PathVariable id: Long): ResponseEntity<UserResponse> {
        val user = userService.getUserById(id)
        return if (user != null) {
            ResponseEntity.ok(user)
        } else {
            ResponseEntity.notFound().build()
        }
    }
    
    @PutMapping("/{id}/email")
    fun updateEmail(
        @PathVariable id: Long,
        @RequestBody emailUpdate: Map<String, String>
    ): ResponseEntity<UserResponse> {
        val newEmail = emailUpdate["email"] ?: return ResponseEntity.badRequest().build()
        val user = userService.updateUserEmail(id, newEmail)
        return if (user != null) {
            ResponseEntity.ok(user)
        } else {
            ResponseEntity.notFound().build()
        }
    }
}

@SpringBootApplication
class UserManagementApplication

fun main(args: Array<String>) {
    runApplication<UserManagementApplication>(*args)
}

类在实际业务中的应用场景

1. 电商订单处理系统

kotlin
// 订单实体类 - 封装复杂的业务逻辑
@Entity
data class Order(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,
    
    val customerId: Long,
    val totalAmount: BigDecimal,
    
    @Enumerated(EnumType.STRING)
    var status: OrderStatus = OrderStatus.PENDING,      
    
    val createdAt: LocalDateTime = LocalDateTime.now(),
    var updatedAt: LocalDateTime = LocalDateTime.now()
) {
    // 业务方法:订单状态转换
    fun confirm(): Boolean {                            
        return if (status == OrderStatus.PENDING) {
            status = OrderStatus.CONFIRMED
            updatedAt = LocalDateTime.now()
            true
        } else {
            false
        }
    }
    
    // 业务方法:计算订单是否可以取消
    fun canBeCancelled(): Boolean {                     
        return status in listOf(OrderStatus.PENDING, OrderStatus.CONFIRMED)
    }
}

enum class OrderStatus {
    PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
}

2. 配置管理类

kotlin
// 应用配置类 - 管理系统配置
@ConfigurationProperties(prefix = "app")
@Component
data class AppConfig(                                   
    val name: String = "用户管理系统",
    val version: String = "1.0.0",
    val database: DatabaseConfig = DatabaseConfig(),
    val security: SecurityConfig = SecurityConfig()
)

data class DatabaseConfig(
    val maxConnections: Int = 10,
    val connectionTimeout: Long = 5000
)

data class SecurityConfig(
    val jwtSecret: String = "default-secret",
    val tokenExpiration: Long = 86400000 // 24小时
)

最佳实践与常见陷阱

✅ 最佳实践

  1. 使用 data class 处理数据传输
kotlin
// 推荐:使用 data class 自动生成 equals、hashCode、toString
data class UserDto(val id: Long, val name: String)     

// 不推荐:普通类需要手动实现这些方法
class UserClass(val id: Long, val name: String)        
  1. 合理使用 val 和 var
kotlin
data class Product(
    val id: Long,           // 不可变 - ID 通常不应该改变
    val name: String,       // 不可变 - 商品名称
    var price: BigDecimal,  // 可变 - 价格可能会调整
    var stock: Int          // 可变 - 库存会变化
)
  1. 使用伴生对象创建工厂方法
kotlin
data class User(val id: Long, val email: String) {
    companion object {
        fun createNew(email: String): User {            
            return User(id = 0, email = email)
        }
        
        fun fromDatabase(id: Long, email: String): User {
            return User(id = id, email = email)
        }
    }
}

⚠️ 常见陷阱

陷阱1:过度使用可变属性

kotlin
// 危险:所有属性都是可变的
data class User(
    var id: Long,           
    var email: String,      
    var createdAt: LocalDateTime
)

// 安全:只有真正需要修改的属性才用 var
data class User(
    val id: Long,           
    var email: String,      
    val createdAt: LocalDateTime
)

陷阱2:忘记处理空值

kotlin
// 危险:可能导致 NullPointerException
fun processUser(user: User?) {
    println(user.email)     
}

// 安全:正确处理空值
fun processUser(user: User?) {
    user?.let {             
        println(it.email)
    } ?: println("用户为空")
}

进阶特性预览

继续学习的方向

掌握了基础类的概念后,你可以继续探索:

  • 继承(Inheritance):创建类的层次结构
  • 接口(Interfaces):定义契约和规范
  • 密封类(Sealed Classes):受限的类层次结构
  • 内联类(Inline Classes):零开销的包装器

总结:类的价值与意义 🎯

通过本章的学习,我们了解到:

  1. 类是面向对象编程的基础:它让我们能够将现实世界的概念转化为代码结构
  2. Kotlin 的类语法简洁而强大:相比传统语言,Kotlin 大大减少了样板代码
  3. 在 SpringBoot 开发中:类是构建实体、服务、控制器等核心组件的基础
  4. 正确使用类能够
    • 提高代码的可读性和维护性
    • 实现更好的代码复用
    • 建立清晰的业务模型

IMPORTANT

记住,类不仅仅是语法特性,更是一种思维方式。学会用面向对象的思维分析问题、设计解决方案,这将是你编程路上的重要里程碑!

现在,拿起键盘,开始用 Kotlin 的类来构建你的第一个 SpringBoot 应用吧! 🚀