kotlin基本语法官网
1. 变量
‘val
’ 声明 仅被赋值一次的变量,初始化后不能重新赋值
。
‘var
’ 声明 可以重新分配的变量,可以在初始化后更改其值
。
Kotlin 支持类型推断
,可以省略变量名后的类型。
val x: Int = 5
var x: Int = 5
val x = 5
变量只有在初始化后才能使用。
先声明变量,然后再初始化,这种情况必须指定数据类型。
val c: Intc = 3
2. 函数
'=' 代表 花括号
。【特别之处】
fun sum(a: Int, b: Int) = a + b
- ‘Unit’ 类型 代表该函数没有返回值
fun printSum(a: Int, b: Int): Unit {println("sum of $a and $b is ${a + b}")
}
- 函数返回值也可以省略
fun printSum(a: Int, b: Int) {println("sum of $a and $b is ${a + b}")
}
3.类
类的属性可以在其声明或主体中列出
。【特别之处】
// 这种写法 类似于 函数写法
class Rectangle(val height: Double, val length: Double) {val perimeter = (height + length) * 2
}
- 构造函数
主构造函数
次构造函数
默认构造函数 - 继承
‘open
’ 标记 一个类可被继承。
4.字符串
- ‘
$
’ 在字符串中用于字符串模板的插值,这允许将 变量或表达式的值 插入到字符串中。这种特性被称为‘字符串模板
’。 ''用于表示单个字符的字符常量,""用于表示字符串,它可以包含多个字符
。【特别之处】
5.数组 和 列表
【特别之处】
数组:
- 需要明确指定元素类型。
- 不可变长度。
列表:
- 可以包含不同类型的元素,但建议保持列表元素类型的一致性。
- 不可变列表 和 可变列表。
6.循环
- for循环
for (item in items) {println(item)}
- while 循环
while (index < items.size) {println("item at $index is ${items[index]}")index++}
7.when 表达式
【特别之处】
when 表达式
与 其他语言中的 switch-case有相似之处,但也有很多不同点。
when 表达式更加灵活。它可以接受各种类型的参数,包括区间、类型判断等,而不仅仅局限于整数或枚举类型等特定类型。
// 区间判断
when (num) {in 1..5 -> println("Number is between 1 and 5.")else -> println("Number is outside these ranges.")
}// 类型判断when (obj) {is Int -> println("It's an integer.")is String -> println("It's a string.")is Double -> println("It's a double.")else -> println("Unknown type.")}//任意表达式作为条件
val str = "Hello"
when {str.length > 5 -> println("String is long.")str.length < 5 -> println("String is short.")else -> println("String is just right.")
}
8.区间
【特别之处】
区间内 用 ‘in
’
区间外 用 ‘!in
’
‘a..b’ 表示闭区间
[a,b]
// 检测某个数字是否在指定区间内if (x in 1..6) {println("fits in range")}// 区间迭代for (x in 1..5) {println(x)}// 数列迭代 【特别之处】
for (x in 1..10 step 2) {print(x) // 1、3、5、7、9
}for (x in 9 downTo 0 step 3) {print(x) // 9、6、3、0
}
9.Lambda 表达式
可以理解为一种简洁的、可以作为参数传递或者作为函数结果返回的匿名函数。
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")fruits.filter { it.startsWith("a") }.sortedBy { it }.map { it.uppercase() }.forEach { println(it) }
10.支持空安全
(类似于Dart)
写法:
1.变量类型: Int?
2.‘?:
’ 用来进行空值判断并提供一个默认值,类似于Dart中的‘??’。 files?.size ?: "empty"
11.类型检测与自动类型转换
‘is
’ 操作符检测一个表达式是否为某类型的一个实例。
if (obj is String) {// `obj` 在该条件分支内自动转换成 `String`return obj.length}
12.延迟属性
使用‘by lazy
’通常是在属性声明的地方,后面跟着一个 lambda 表达式来计算属性的值。
仅在首次访问时计算。一旦属性被初始化,后续的访问将直接返回已初始化的值,不会再次执行初始化的代码
。
【对比】
与Dart语言中的late还不太一样,late表示该变量将在稍后被初始化。
Kotlin 的by lazy是线程安全的;Dart 的late变量不是自动线程安全的。
val p: String by lazy {println("Calculating string...")"This is a lazy-evaluated string."}println("Before accessing p.")println(p)println("After accessing p.")println(p) // 再次访问不会重新计算
13.扩展函数
fun 接收者类型.扩展函数名(参数列表)
: 返回类型 {
// 函数体
}
类似于Dart语言中的extension…on
// 扩展函数
fun String.spaceToCamelCase() { …… }
// 调用
"Convert this to camelcase".spaceToCamelCase()
14.伴生对象
【特别之处】
companion object
{ … }
1.定义'方法'和'属性'
,可以’通过类名直接访问
’。(类似于其他语言中的静态成员)
2.在类加载时'只会创建一次'
。(可以实现单例)
3.包含初始化块init
{ … } ,对于需要在类加载时进行的初始化操作非常有用。
4.可以添加拓展(MyClass.Companion.扩展函数名
)。
class MyClass {companion object {// 静态属性或方法val someProperty: String = "This is a companion object property."fun someMethod() {println("This is a companion object method.")}// 初始化块(会优先执行)init {println("Companion object initialized.")}}
}// 为伴生对象添加拓展
fun MyClass.Companion.someExtensionFunction() {println("This is an extension function for the companion object.")
}// 调用
fun main() {println(MyClass.someProperty)MyClass.someExtensionFunction()
}
15.单例
- 对象声明方式
‘object
’ 声明单例
object Singleton {val someProperty: String = "This is a singleton property."fun someFunction() {println("This is a singleton function.")}
}
- 懒汉式单例(使用委托属性)
class SingletonLazy private constructor() {companion object {// 首次访问SingletonLazy.instance时才会创建实例val instance: SingletonLazy by lazy { SingletonLazy() }}
}
- 饿汉式单例
class SingletonEager private constructor() {companion object {// 在类加载时就创建实例(仅创建一次)val instance = SingletonEager()}
}
16.值类
'@JvmInline’注解作用 :
- 性能优化。
在 Java 虚拟机(JVM)运行时,带有@JvmInline注解的值类实例不会像普通的类对象那样占用额外的内存空间和带来对象创建的开销。它会更像直接使用那个字符串本身,从而提高程序的性能。 - 简洁性和可读性。
只有 JVM 后端才需要该注释
。
@JvmInline
value class EmployeeId(private val id: String)class Employee(val name: String, val employeeId: EmployeeId)fun main() {// 创建员工 ID 值类实例val employeeId = EmployeeId("E12345")// 创建员工对象并传入员工 ID 值类实例val employee = Employee("John Doe", employeeId)println("Employee name: ${employee.name}, Employee ID: ${employee.employeeId.id}")
}
17.抽象类
- 抽象方法没有实现体,只有方法签名。
子类必须实现抽象类中的所有抽象方法
。- 非抽象方法,若想要在子类中重写,必须使用
open
。 - 抽象类可以包含具体方法和属性,这些方法和属性可以被子类继承和使用。
- 创建一个 匿名内部类的实例 来实现 抽象类。
// 抽象类 Animal
abstract class Animal {// 抽象方法abstract fun makeSound()val someProperty: Int = 10// 非抽象方法,若想要在子类中重写,必须使用openopen fun someMethod() {println("This is a method in the abstract class.")}
}// 子类Dog ,继承抽象类Animal
class Dog : Animal() {override fun makeSound() {println("Woof!")}override fun someMethod(){println("dog someMethod")}
}// 调用
fun main() {val dog = Dog()dog.makeSound()dog.someMethod()// 创建一个匿名内部类的实例来实现抽象类var cat = object : Animal(){override fun makeSound() {println("Meow!")}}cat.makeSound()
}
18.标准函数
1. run
{ … }
- 可以包含任意的表达式和语句。
最后一个表达式的值 将作为 run的返回值
。
// ‘data’ 修饰 类 ,会为这个类自动生成一些实用的函数和特性data class Person(val name: String, val age: Int)val person = Person("Alice", 30).run {// Person 类如果没有data的修饰,这里打印的信息不易读。// 不易读 ——> Created person: FileKt$main$Person@3941a79c// 易读 ——> Created person: Person(name=Alice, age=30)println("Created person: $this")this}
2. let
{ … }
安全地调用可能为 null 的对象
。
(如果一个变量可能为 null,使用 let 函数可以在确保变量不为 null 的情况下执行一段代码块。)- 执行特定操作,并返回一个值。
- 临时变量和代码组织。
(使代码更易于理解和维护)
// 1. 安全调用val str: String? = "123"str?.let {println(it.length)}// 2.链式调用val str = "hello world".let {println(it)it.toUpperCase()}.let {println(it)it.length}println(str)// 3. 增强代码可读性data class Person(val name: String, val age: Int)val person = Person("Alice", 30)val formattedInfo = person.let { p ->val nameLength = p.name.lengthval ageString = p.age.toString()"Name length: $nameLength, Age: $ageString"}println(formattedInfo)
3. with
{ … }
- 简化对象属性和方法的访问。
(在一个代码块中提供对该‘对象的属性和方法的直接访问’) - 临时对象的操作。
// 1.提高代码的可读性和简洁性data class Person(val name: String, val age: Int)val person = Person("Alice", 30)with(person) {// 无需每次都写成person.name和person.ageprintln("Name: $name, Age: $age")}// 2.用完即丢弃 with(StringBuilder()) {append("Hello")append(" World")println(this.toString())}
4. apply
{ … }
- 特别适用于
对象的初始化
过程。 - 在一个代码块中对对象进行一系列的设置操作,
最后返回被操作的'对象本身'(主动返回的
,不需要手动设置)。
data class Rectangle(var width: Int, var height: Int)val rectangle = Rectangle(10, 20).apply {width = 15}.apply {height = 25}println(rectangle)
5. use
{ … }
- 资源管理的作用域函数。
在代码块执行完毕后,自动关闭所使用的资源
。
val stream = Files.newInputStream(Paths.get("/some/file.txt"))try {stream.use { inputStream ->// 在这里使用输入流进行操作,如果发生异常,资源仍然会被正确关闭}} catch (e: IOException) {// 处理异常}
6. also
{ … }
接受一个对象作为参数,并在一个代码块中允许对该对象执行一些额外的操作
,同时返回原始‘对象本身’
。
data class Rectangle(val width: Int, val height: Int)val rectangle = Rectangle(10, 20).also {println("Rectangle: $it")}.also {// 这里可以执行一些不改变对象的操作,比如记录日志}