> 技术文档 > kotlin部分常用特性总结

kotlin部分常用特性总结


Kotlin中类和对象初始化

  • 添加open关键字代表可以被继承
  • Any 是所有类的父类,类似Object,包含 equals() hashCode() toString()方法
  • constructor 关键字代表构造函数, constructor关键字可以去掉
  • 辅助构造函数是类中定义的额外构造函数,用于提供多种对象初始化方式
  • 主构造函数可以在类头部分声明,以及通过 init 块或属性直接赋值
class User(性格: String, 长相: String, 声音: String) : Human(性格, 长相, 声音)class User2(name: String) : Human2(name)open class Human constructor(var 性格: String, var 长相: String, var 声音: String) : Any() { //对象创建时调用,构造方法的方法体 init { println(\"new 了一个${this.javaClass.simpleName}, ta性格:$性格, 长相:$长相, 声音:$声音\") } override fun toString(): String { return \"${性格} 性格\" }}open class Human2 { val name: String val age: Int constructor(name: String) : this(name, 0) { // 调用主构造函数或另一个辅助构造函数 } constructor(name: String, age: Int = 18) { // 辅助构造函数 this.name = name this.age = age val user: User = User(\"温柔\", \"甜美\", \"动人\") val value: String? = getName() println(value!!.length) }}

空类型和智能类型转换

  • ?.在遇到null时会静默跳过执行(返回null)
  • !!在遇到null时会立即抛出异常 (当对可空变量使用!!时,编译器会假定该变量不为null)
fun getName(): String? {// ? 表示返回值可以为空 return \"na\"//null}fun main(args: Array) { val str: String? = null // ?.在遇到null时会静默跳过执行(返回null) // !!在遇到null时会立即抛出异常 (当对可空变量使用!!时,编译器会假定该变量不为null) //val length = str!!.length // 应尽量避免使用!!,推荐替代方案包括: // 优先使用val声明不可变变量 // 对延迟初始化变量使用 lateinit. var用lateinit 延迟初始化,val用lazy lateinit var q: String // 使用Elvis操作符?:提供默认值或者return //Elvis操作符?: 结构:表达式A ?: 表达式B //当表达式A非null时返回A的值,否则返回表达式B的结果 // 例如: val length2 = str?.length ?: 0 val name: String = getName() ?: return println(name.length) main2(args)}

区间 Range,表示范围

//val:用于运行时常量,相当于Java的final字段,支持任何类型且仅初始化一次//const:用于编译时常量,相当于Java的public static final字段,可通过类名直接访问。//编译时确定值:const修饰的常量值必须在编译时确定,不能通过运行时计算或动态赋值。//类型限制:仅支持基本类型(如int、double、string)和字符串。//存储位置:必须声明在顶层(如包级可见变量)或伴生对象(companion object)中val range: IntRange = 0..1024 // [0, 1024]val range_exclusive: IntRange = 0 until 1024 // [0, 1024) = [0, 1023]val a = (50 in range) // (i in range)判断i是否在区间中

Unit

在 Kotlin 中,Unit 是一个特殊的类型,类似于 Java 中的 void,但有以下关键区别:

  • Unit 是一个实际存在的类型(单例对象),而 void 只是关键字
  • 当函数不返回有意义的值时,Kotlin 会隐式返回 Unit
  • Unit 的实例可以用 Unit 或 () 表示
fun printMessage(msg: String): Unit { // 这里的 : Unit 可以省略 println(msg) // 隐式返回 Unit}fun printUsage() { println(\"请传入两个整型参数,例如 1 2\") // (Any?) -> Unit} // ()->Unitval sum = { arg1: Int, arg2: Int -> println(\"$arg1 + $arg2 = ${arg1 + arg2}\") arg1 + arg2}// (Int, Int) -> Intval printlnHello = { println(::printUsage is ()-> Unit) println(\"Hello\")}// ()-> Unitval int2Long = fun(x: Int): Long { return x.toLong()}

继承与实现

  • 父类需要 open 才可以被继承
  • 父类方法、属性需要 open 才可以被覆写
  • 接口、接口方法、抽象类默认为 open
  • 覆写父类(接口)成员需要 override 关键字
  • class D: A(),B,C
  • 注意继承类时实际上调用了父类构造方法
  • 类只能单继承,接口可以多实现

继承之接口代理(基于 by 关键字)

by关键字在Kotlin中用于**委托模式**,它允许你将一个类的某个属性或方法的实现委托给另一个对象。- 它可以让我们在不直接实现接口的情况下,通过委托的方式间接实现接口 通过 by 将接口实现委托给其他对象,无需手动编写代理类

class SeniorManager(val driver: Driver, val writer: Writer): Driver by driver, Writer by writerclass CarDriver: Driver { override fun drive() { println(\"开车呢\") }}class PPTWriter: Writer { override fun write() { println(\"做PPT呢\") }}interface Driver{ fun drive()}interface Writer{ fun write()}fun main3(args: Array) { val driver = CarDriver() val writer = PPTWriter() val seniorManager = SeniorManager(driver, writer) seniorManager.drive() seniorManager.write()}

接口方法冲突

  • 接口方法可以有默认实现
  • 签名一致且返回值相同的冲突
  • 子类(实现类)必须覆写冲突方法
  • super.方法名
abstract class A{ open fun x(): Int = 5}interface B{ fun x(): Int = 1}interface C{ fun x(): Int = 0}class D(var y: Int = 0): A(), B, C{ override fun x(): Int { println(\"call x(): Int in D\") if(y > 0){ return y }else if(y < -200){ return super.x() }else if(y < -100){ return super.x() }else{ return super.x() } }}//3 5 1 0 fun main(args: Array) { println(D(3).x()) println(D(-10).x()) println(D(-110).x()) println(D(-10000).x())}

可见性对比

模块通常指一组共同编译的 Kotlin 文件(如 Gradle 模块或 IntelliJ 模块)

kotlin java private private protected protected - default(包内可见) internal(模块内可见,模块化开发的核心修饰符) - public public

Object 关键字

object 关键字用于实现‌单例模式‌、‌伴生对象‌和‌对象表达式‌(匿名对象),是 Kotlin 特有的简化设计模式的语法糖。以下是其三大核心用途及示例:

  1. 单例模式(对象声明)‌
    直接通过 object 声明线程安全的单例:
object DatabaseManager { private val connection = \"DB_Connection\" fun query(sql: String) = println(\"Executing: $sql via $connection\")}// 使用(全局唯一实例)fun main() { DatabaseManager.query(\"SELECT * FROM users\") // 输出: Executing: SELECT * FROM users via DB_Connection}

特点:
* 只有一个实例的类
* 首次访问时延迟初始化(线程安全)
* 不能自定义构造函数, 可继承父类 可实现接口

  1. 伴生对象
  • 每个类可以对应一个伴生对象
  • 伴生对象的成员全局独一份 , 相当于静态方法 静态属性
class Latitude private constructor(val value: Double){ companion object{ @JvmStatic fun ofDouble(double: Double): Latitude{ return Latitude(double) } fun ofLatitude(latitude: Latitude): Latitude{ return Latitude(latitude.value) } @JvmField val TAG: String = \"Latitude\" }}
  1. 匿名对象
  • 每次调用都会创建新对象
  • 可同时继承类和实现接口(如 object : ClassA(), InterfaceB
  • 注意:object 与 class 不同,不能实例化(本身就是实例)
 interface ClickListener { fun onClick() } fun setClickListener(listener: ClickListener) { listener.onClick() } fun main() { var counter = 0 setClickListener(object : ClickListener { override fun onClick() { println(\"Clicked ${++counter} times\") // 捕获并修改外部变量 } }) }

扩展成员

  • 为现有类添加方法、属性
  • fun X.y(): Z {... }
  • val x.m 注意扩展属性不能初始化,类似接口属性
  • Java 调用扩展成员类似调用静态方法
 operator fun String.times(int: Int): String{ val stringBuilder = StringBuilder() for(i in 0 until int){ stringBuilder.append(this) } return stringBuilder.toString() } val String.a: String get() = \"abc\" var String.b: Int set(value) { } get() = 5 //abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc //5 fun main(args: Array) { println(\"abc\" * 16) \"abc\".b = 5 println(\"abc\".b) }

operator关键字

operator 关键字用于‌重载运算符‌或‌约定特定函数‌,让类实例支持类似基础类型的操作(如 +、[]、in 等)

运算符重载‌

通过重载预定义的运算符函数,使对象支持算术、比较等操作

data class Point(val x: Int, val y: Int) { // 重载 \"+\" 运算符 operator fun plus(other: Point): Point { return Point(x + other.x, y + other.y) }}fun main() { val p1 = Point(1, 2) val p2 = Point(3, 4) println(p1 + p2) // 输出: Point(x=4, y=6)}
运算符 对应函数名 示例表达式 + plus a + b - minus a - b [] get a[i] in contains a in b == equals a==b
约定函数

operator 还可用于标记‌特定名称的函数‌,实现与语言特性的交互:

  • 解构声明(Destructuring)
class User(val name: String, val age: Int) { operator fun component1() = name // 解构为 (name, age) operator fun component2() = age}fun main() { val user = User(\"Alice\", 25) val (name, age) = user // 解构赋值 println(\"$name, $age\") // 输出: Alice, 25}
  • 迭代器支持
class Counter(val range: IntRange) { operator fun iterator(): Iterator = range.iterator()}fun main() { for (i in Counter(1..5)) { // 支持 for-in 循环 print(\"$i \") // 输出: 1 2 3 4 5 }}
注意事项‌
  • 不可随意创造运算符‌:只能重载 Kotlin 预定义的运算符47。
  • 一致性要求‌:如 plus 不应修改原对象,应返回新实例35。
  • 与扩展函数结合‌:可为现有类添加运算符支持
operator fun Int.times(str: String) = str.repeat(this)fun main() { println(3 * \"Hi \") // 输出: Hi Hi Hi }

属性代理

懒加载 lazy
  • 延迟到首次访问时执行
  • 线程安全模式‌:默认 LazyThreadSafetyMode.SYNCHRONIZED,可选 PUBLICATION(允许多线程初始化)或 NONE(单线程)
class Delegates{ val hello by lazy { \"HelloWorld\" } val hello0 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { \"HelloWorld\" } val hello2 by X() var hello3 by X()}
基本用法
// val 属性‌:只需实现 getValue ‌// var 属性‌:需同时实现 getValue 和 setValueclass X{ private var value: String? = null operator fun getValue(thisRef: Any?, property: KProperty): String { println(\"getValue: $thisRef -> ${property.name}\") return value?: \"\" } operator fun setValue(thisRef: Any?, property: KProperty, value: String){ println(\"setValue, $thisRef -> ${property.name} = $value\") this.value = value }}fun main6(args: Array) { val delegates = Delegates() println(delegates.hello) println(delegates.hello2) println(delegates.hello3) delegates.hello3 = \"value of hello3\" println(delegates.hello3) println(delegates.hello)}//HelloWorld//getValue: com.spro.globalsearch.Delegates@1593948d -> hello2////getValue: com.spro.globalsearch.Delegates@1593948d -> hello3////setValue, com.spro.globalsearch.Delegates@1593948d -> hello3 = value of hello3//getValue: com.spro.globalsearch.Delegates@1593948d -> hello3//value of hello3//HelloWorld

数据类DataClass

  • 自动生成标准方法: 数据类会自动生成 equals()、hashCode()、toString()、copy() 等方法,普通类需手动实现
  • 主构造函数要求: 必须至少有一个参数,且参数需标记为 val 或 va, 普通类无此限制
  • 解构声明支持 数据类自动支持解构,可直接将属性拆分为变,普通类则需手动实现 componentN()
  • 不可变性推荐‌: 属性通常声明为 val(不可变),但支持 var(可变)‌
  • 继承限制‌ 数据类不能是 abstract、open、sealed 或 inner 类‌
  • 无无参构造函数 需显式定义默认值或辅助构造函数‌
应用
  • 数据传输对象 如 JSON 解析后的数据实体‌
  • 简化数据操作 利用 copy() 实现不可变对象的修改‌ val user2 = user1.copy(age = 26)
data class Country(val id: Int, val name: String)data class Country2(var id: Int, var name: String)//component 组件class ComponentX{ operator fun component1(): String{ return \"您好,我是\" } operator fun component2(): Int{ return 1 } operator fun component3(): Int{ return 1 } operator fun component4(): Int{ return 0 }}fun main7(args: Array) { //componentN解构声明 val china = Country(0, \"中国\") println(china)// Country(id=0, name=中国) println(\"${china.component1()} ------ ${china.component2()} \")//0 ------ 中国 val (idx, name) = china //解构赋值 println(\"$idx ------ $name\")//0 ----- 中国 val componentX = ComponentX()//解构赋值 val (a, b, c, d) = componentX println(\"$a $b$c$d\")//您好,我是 110}

内部类

静态内部类与非静态内部类的区别:到底是否持有外部类的状态 (非静态内部类持有外部类的状态,可以访问外部类的属性)

open class Outter{ val a: Int = 0 class InnerDefaultStatic{ } //非静态内部类 inner class Inner{ val a: Int = 5 fun hello(){ println(this@Outter.a) } }}interface OnClickListener{ fun onClick()}class View{ var onClickListener: OnClickListener? = null}fun main(args: Array) { val innerDefaultStatic = Outter.InnerDefaultStatic() val inner = Outter().Inner() val view = View() //匿名内部类看上去没有名字,但是编译生成字节码文件有自己的ID,类似Outter$1.class view.onClickListener = object : Outter(), OnClickListener{ override fun onClick() { } }}

枚举类

  • 实例可数的类,注意枚举也是类
  • 可以修改构造,添加成员
  • 可以提升代码的表现力,也有一定的性能开销
  • 实例可数‌指枚举(enum)类型的成员数量固定且不可扩展。
  • 枚举通过enum class声明,其所有成员(如VERBOSE、DEBUG等)均为该类的实例对象,且默认构造函数为私有(private constructor()),因此无法被继承或扩展
enum class LogLevel(val id: Int){ VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5); fun getTag(): String{ return \"$id, $name\" } override fun toString(): String { return \"$name, $ordinal\" }} println(LogLevel.DEBUG.ordinal) LogLevel.values().map(::println) println(LogLevel.valueOf(\"ERROR\")) //VERBOSE, 0 //DEBUG, 1 //INFO, 2 //WARN, 3 //ERROR, 4 //ASSERT, 5 //ERROR, 4

密封类

子类可数

sealed class PlayerCmd{}class Play(val url:String,val position:Long =0):PlayerCmd()class Seek(val position: Long): PlayerCmd()object Pause:PlayerCmd()object Resume:PlayerCmd()object Stop:PlayerCmd()enum class PlayerState{ IDLE, PAUSE, PLAYING}