kotlin知识点
2026-07-07 16:45:51 0 举报AI智能生成
kotlin入门详细知识点总结
kotlin
模板推荐
作者其他创作
大纲/内容
基础
基本类型
数字
分支主题
分支主题
注意
(1)kotlin中不支持不同类型的相互调用
(2)不支持8进制
(3)从1.1起支持数字用_分隔,便于识别
val oneMillion = 1_000_000
(4)显示转换:toByte(): Byte、toShort(): Short....
字符
(1)char类型用单引号'1'表示
布尔
true、false
数组
用Array表示,可通过 arrayOf(1,2,3)也可通过arrayOfNulls()
ByteArray
ShortArray
IntArray
使用
// 大小为 5、值为 [0, 0, 0, 0, 0] 的整型数组
val arr = IntArray(5)
// 例如:使用 lambda 表达式初始化数组中的值
// 大小为 5、值为 [0, 1, 2, 3, 4] 的整型数组(值初始化为其索引值),it为迭代的下标
var arr = IntArray(5) { it * 1 }
无符号整型
无符号整型:自 Kotlin 1.3 起才可用
字符串
(1)字符串:不可变,可通过s[0]获取,可通过for迭代循环,可通过+进行连接
(2)通过\n进行转义,通过三个双引号进行多行内容输入
(3)字符串模板:在字符串中使用$加上变量名输出值,也可在${}中任意的表达式
var a = 10
println("${a}") println("${a.length}")
包与导入
默认导入
kotlin.*
kotlin.annotation.*
kotlin.collections.*
kotlin.comparisons.* (自 1.1 起)
kotlin.io.*
kotlin.ranges.*
kotlin.sequences.*
kotlin.text.*
根据目标平台还会导入额外的包
JVM:
java.lang.*
kotlin.jvm.*
JS:
kotlin.js.*
手动导入
import org.example.* // “org.example”中的一切都可访问
import org.example.Message // Message 可访问
import org.test.Message as testMessage // testMessage 代表“org.test.Message”
控制流
if...else
if表达式可以获取返回的值
// 作为表达式
val max = if (a > b) a else b
//也可以是代码块
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
when
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意这个块
print("x is neither 1 nor 2")
}
}
//多个条件符合
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
//任意的表达式
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
//when条件表达式中调用方法或者其他
when (executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
for
for 循环可以对任何提供迭代器(iterator)的对象进行遍历
//循环区间
for (i in 1..3) {
println(i)
}
//循环数组,获取下标
for (i in array.indices) {
println(array[i])
}
//同时获取下标和数据
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
while/do...while
返回与跳转
同样支持continue和break
//跳转至指定标签后面的表达式
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
返回return
//普通的return
//指定标签的return
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部返回到该 lambda 表达式的调用者,即 forEach 循环
print(it)
}
print(" done with explicit label")
}
//返回值并且指定返回标签
return@a 1 意思是返回至a标签处,并且值为1
类与对象
类与继承
·类
含义
(1)类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成
(2)所有的类都有一个共同的超类Any
class Example // 从 Any 隐式继承
(3)如果派生类有一个主构造函数,其基类可以(并且必须) 用派生类主构造函数的参数就地初始化。
(4)如果派生类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数
空类:class Empty
私有的类
//创建一个私有的类
class DontCreateMe private constructor () { /*……*/ }
init初始化块
//加载顺序次构造函数之前
init {
println("First initializer block that prints ${name}")
}
构造函数
主构造函数
//如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
class constructor Person(name: String){}
//声明类型和初始化
class Person(val firstName: String, val lastName=“hello”: String, var age: Int) { /*……*/ }
//如果主构造函数都有默认值,则此时类会默认生成一个无参数的构造函数,它将使用默认值
class Test1(name: String="1",phone: String="12")
次构造函数
//次构造函数,并且必须调用主构造函数
constructor(name: String,sex:Int) : this(name){
println("次构造函数1")
}
创建类
//实例化一个User对象,没有new关键字
User();
继承和重写
(1)kotlin中的一般类默认都是final类,都是不能继承的,除非是abstract的类或者open修饰的类可以被继承
(2)派生类重写父类的方法必须加上override关键字,并且父类只有标记了open关键字的方法,子类才可以重写
override fun getName(){}
(3)如果子类重写的方法不想被再次重写可以加上final关键字修改时
final override getName(){}
属性重写
可以用var属性覆盖val属性,反之则不可以,因为val属性只能有一个get()方法,var可以有get/set方法
抽象类继承非抽象类时,可以用一个抽象成员覆盖一个非抽象的开放成员
超类调用
调用超类的属性、方法用super关键字
内部类调用外部类的超类方法:
super@son.draw() // 调用 Rectangle 的 draw() 实现
继承多个超类时的调用
//如果子类继承的两个超类中有个共同的方法时,则在调用的时候需要声明是哪个超类的方法
super<Person>.getName()
super<Shop>.getName()
伴生对象
含义
(1)伴生对象也可以继承超类或者实现接口
(2)伴生对象也是一个普通的类,具有和普通类相同的功能
单例模式
创建单例模式的对象声明
object singleObj{
fun test(){}
}
伴生对象
fun Test{
companion obj follow{
fun getSome(){
}
}
}
属性与字段
属性
含义:val默认实现getter()方法,var默认实现getter()和setter()方法
//getter()和setter(),并且可以定义可见性或者用注解
public var name: String
get() = "a"
private set(value){}
//getter方法写表达式
val isEmpty: Boolean
get() = this.size == 0
幕后字段
field:隐式的私有变量
延迟属性加载
lateinit var a: Int = 0
编译器常量
const满足的要求
(1)只能用于伴生对象companion object、单例对象object、嵌套类internal object
(2)以val修饰的不可变常量
(3)未自定义getter()
(4)以 String 或原生类型值初始化
覆盖属性
属性的覆盖必须和父类属性保持一致,当然var可以覆盖父类用val修饰的属性,意思就是可以扩展原来的不能减少原来的
委托属性
lazy延迟属性
含义:只有当第一次调用的时候会执行表达式方法,后面再次调用是只会获取记录的值
实例
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main() {
println(lazyValue)
println(lazyValue)
}
分支主题
可观察属性
含义:采用Delegates.observable在调用该属性赋值完成之后时会执行表达式,此表达式会默认包含是三个属性(属性,旧值、新值),此时的属性的值也会随之改变
实例<br>var obserName: String by Delegates.observable("默认值"){<br> prop,old,new -><br> println("prop:$prop,old:$old,new:$new")<br> }<br>val test3 = Test3()<br> test3.obserName = "aa"<br> test3.obserName = "bb"<br><br>输出结果:<br>prop:var main.java.test.Test3.obserName: kotlin.String,old:第一次,new:aa<br>prop:var main.java.test.Test3.obserName: kotlin.String,old:aa,new:bb
含义:采用Delegates.vetoable在调用该属性赋值完成之后时会执行表达式,此表达式会默认包含是三个属性(属性,旧值、新值),但是此表达式必须要返回一个布尔型的值,如果为true的话,属性值修改生效,若为false则修改的值无效,此时的属性值为默认值
实例
var obserName1: String by Delegates.vetoable("默认值",{
prop1,old1,new1 ->
println("prop:$prop1,old:$old1,new:$new1")
1==2
})
val test3 = Test3()
test3.obserName1 = "aa"
test3.obserName1 = "bb"
输出结果
prop:var main.java.test.Test3.obserName1: kotlin.String,old:默认值,new:aa
prop:var main.java.test.Test3.obserName1: kotlin.String,old:默认值,new:bb
委托延迟属性:默认值
接口
含义:接口中可以定义方法以及定义方法的也可以有具体实现,接口无法保存状态,可以定义用abstract修饰的属性(默认abstract修饰可不写)不能进行初始化或者需要初始化的属性必须定义getter()来访问|
实现类必须重写未初始化的属性,方法的实现是不必须的
访问修饰符
含义:public、protected、private、internal
扩展
扩展属性
如果是非抽象的属性必须显示的写出getter和setter
val <T> List<T>.lastIndex: Int
get() = size - 1
扩展方法
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // “this”对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
伴生对象扩展
class MyClass {
companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
数据类
含义:
(1)专用于保存数据的类,通过主构造函数的方式定义属性,
(2)必须用var/val声明且必须至少有一个参数,有点儿类似java的PO等实体类
(3)数据类不能是开放的(open)、抽象的(abstract)、密封的(sealed)、内部的(inner)
data class User(val name: String, val age: Int)
copy
可以复制数据类的一个副本,并且可给新的类设置新的属性值
val test21 = DataClassTest("张三", "sss",2)
var test211 = test21.copy(name = "李四")
数据类解构声明
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // 输出 "Jane, 35 years of age"
Pair
可以创建具有两个参数的对象,类似于Map不限制数据的类型
val pair = Pair<Int, String>(12, "hello")
Triple
val triple = Triple(1, 2.2, "xx")
val (x,y,z) = Triple(1, 2.2, "xx")
println("one:${triple.first},two:${triple.second},three:${triple.third}")
println("x:${x},y:${y},z:${z}")
密封类
含义:要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明
泛型
内部类
嵌套类
含义:嵌套类不可以引用外部类的属性和方法,在调用的时候不需要实例化外部类,可直接进行调用
class InnerTest {
var name:String = "1"
class InnerTest2{
var name:String = "2"
}
}
//调用
InnerTest.InnerTest2().name
内部类
含义:内部类可以使用外部类的引用,为了区分调用的对象,调用外部类时需要用this@外部类名来调用
class Inner2Test {
var name:String = "3"
var p = 0
inner class Inner2Test2{
var name:String = "4"
var x = 10
fun get() = this@Inner2Test.name
fun getValue() = this.x
}
}
//调用
Inner2Test().Inner2Test2().get()
枚举类
含义:
(1)若枚举类只有一个属性时,不需要构造函数,否则需要些主构造函数
(2)也可以实现接口
class enum TestEnum(type:Int,introduce:String){
QQ(1,“QQ”),WX(2,"WX")
}
类型别名
typealias
集合
构造集合
创建集合的最常用方法是使用标准库函数 listOf<T>()、setOf<T>()、mutableListOf<T>()、mutableSetOf<T>()。
val numbersSet = setOf("one", "two", "three", "four")
空集合
emptyList()、emptySet() 与 emptyMap()。 创建空集合时,应指定集合将包含的元素类型。
val empty = emptyList<String>()
list 的初始化函数
接受 List 的大小与初始化函数的构造函数,该初始化函数根据索引定义元素的值。
val doubled = List(3, { it * 2 }) // 如果你想操作这个集合,应使用 MutableList
println(doubled) //[0, 2, 4]
具体类型构造函数
val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)
集合复制
使用复制函数toList()、toMutableList()、toSet()、mapOf()、mutableMapOf() 等等
调用toList()、toSet()等等...复制出来的集合,在改变源集合时,副本不会改变
给集合创建一个新的应用,当新的应用改变时其他的所有应用也会跟着改变
var listOf = mutableListOf(1, 2, 3)
var copyListOf = listOf.toMutableList()
listOf.add(4)
copyListOf.add(5)
println("copyListOf:$copyListOf")
println("listOf:$listOf")
copyListOf:[1, 2, 3, 4, 5]
listOf:[1, 2, 3, 4, 5]
迭代器
iterator
val numbers = listOf("one", "two", "three", "four")
val numbersIterator = numbers.iterator()
while (numbersIterator.hasNext()) {
println(numbersIterator.next())
}
for 循环
val numbers = listOf("one", "two", "three", "four")
for (item in numbers) {
println(item)
}
forEach() 函数
val numbers = listOf("one", "two", "three", "four")
numbers.forEach {
println(it)
}
List的正向和反向迭代器
val numbers = listOf("one", "two", "three", "four")
val listIterator = numbers.listIterator()
while (listIterator.hasNext()) listIterator.next()
println("Iterating backwards:")
while (listIterator.hasPrevious()) {
print("Index: ${listIterator.previousIndex()}")
println(", value: ${listIterator.previous()}")
}
可变集合迭代时可通过remove()删除、add()添加、set()修改值,add和set需要使用listIterator()迭代器
val numbers = mutableListOf("one", "two", "three", "four")
val mutableIterator = numbers.iterator()
mutableIterator.next()
mutableIterator.remove()
println("After removal: $numbers")
区间和数列
rangeTo() 会辅以 in 或 !in 函数。
if (i in 1..4) { // 等同于 1 <= i &amp;&amp; i <= 4
print(i)
}
反向迭代数字
for (i in 4 downTo 1) print(i)
固定增长值setp
for (i in 1..8 step 2) print(i)
for (i in 8 downTo 1 step 2) print(i)
迭代至不包含其结束元素的数字区间
for (i in 1 until 10) { // i in [1, 10), 10被排除
print(i)
}
数列实现 Iterable<N>,其中 N 分别是 Int、Long 或 Char
println((1..10).filter { it % 2 == 0 })
序列
val numbersSequence = sequenceOf("four", "three", "two", "one")
List转sequence
val numbers = listOf("one", "two", "three", "four")
val numbersSequence = numbers.asSequence()
生成序列
生成无限序列
val oddNumbers = generateSequence(1) { it + 20 } // `it` 是上一个元素
println(oddNumbers.take(100).toList())
如果没有显示的调用take方法,便不会生成序列,不能调用count()方法否则会一直生成
根据条件生成
有限序列
提供一个函数,该函数在需要的最后一个元素之后返回 null。
val oddNumbersLessThan10 = generateSequence(1) { if (it < 10) it + 2 else null }
println(oddNumbersLessThan10.count())
List操作
list获取
get(index)
[index]
写操作
add(index,value)
更新操作
[index] = value
替换所有
fill(value)
删除
removeAt(index)
Set操作
union合并
SetA union SetB
交集获取
SetA intersect SetB
差集获取
SetA subtract SetB
Map操作
初始化
mapOf("one" to 1, "two" to 2, "three" to 3)
取值、添加
println(numbersMap.get("one"))
println(numbersMap["one"])
numbers.put("three",3)
过滤filter
numbersMap.filter { (key, value) -> key.endsWith("1") &amp;&amp; value > 10}
根据键过滤filterKeys
根据值过滤filterValues
不可变Map添加与删除方式,
原先的Map不会改变,
会将改变的Map重新返回
plus
map新加的数据,如果原有的数据存在相同键值
则替换掉原来的值
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap + Pair("one", 10))
minus
根据键值删除数据,
删除不存在的键不会报错,
并且返回新的Map,]
根据一个键删除数据
val numbersMap1 = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap1 - "one")
根据多个键删除
println(numbersMap1 - listOf("two", "four"))
可变Map
添加put、putAll
删除remove
函数与Lambda表达式
函数
含义:
(1)用关键字fun声明
(2)如果方法没有返回值则不需要声明返回类型,如果有返回则必须定义方法的返回类型
方法重写
override fun test():String{
}
重写父类的方法,如果父类方法有默认值,
则子类重写该方法时不能定义默认值
函数调用
fun test(){}
test()
函数参数可以有默认值,设置了默认值的参数在调用方法的时候可以不传递该参数
fun test(name:String="james")
函数体
单表达式,可不定义返回类型
fun test() = 2+20
代码块,必须定义返回类型
fun test():String{
}
可变数量的方法参数用vararg修饰,并且
只有一个参数被标记为vararg,可变参数放在最后面
fun test(sex: Int,vararg name:String):Any{
}
中缀函数
infix fun infixFun(name: String){
println("中缀函数:$name")
}
//调用
test3 infixFun "james"
test3 infixFun("james")
test3.infixFun("james")
局部函数,在函数的内部再定义
一个函数,内部函数可以访问外部函数的变量,
外部不能调用内部的函数
fun innerFun(){
fun inner1Fun(){
}
}
泛型函数
fun <T> singletonList(item: T): List<T> { /*……*/ }
内联函数inline
扩展函数
fun String.sumStr():Any{
}
尾递归函数tailrec
lambda 表达式
->
内联函数
其他
解构声明
下划线用于未使用的变量,
对于以这种方式跳过的组件,
不会调用相应的 componentN()
操作符函数。
val (_, status) = getResult()
类型检测与类型转换
类型检测
is 与 !is 操作符
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // 与 !(obj is String) 相同
print("Not a String")
}
智能转换
fun demo(x: Any) {
if (x is String) {
print(x.length) // x 自动转换为字符串
}
}
智能转换规则
val 局部变量——总是可以,局部委托属性除外;
val 属性——如果属性是 private 或 internal,或者该检测在声明属性的同一模块中执行。智能转换不适用于 open 的属性或者具有自定义 getter 的属性;
var 局部变量——如果变量在检测和使用之间没有修改、没有在会修改它的 lambda 中捕获、并且不是局部委托属性;
var 属性——决不可能(因为该变量可以随时被其他代码修改)。
类型转换
不安全转换,
若为空会抛出
异常
val x: String = y as String
安全转换,若
为空则返回的是null
val x: String? = y as String?
this表达式
在类的成员中,this 指的是该类的当前对象。
在扩展函数或者带有接收者的函数字面值中, this 表示在点左侧传递的 接收者 参数。
class A { // 隐式标签 @A
inner class B { // 隐式标签 @B
fun Int.foo() { // 隐式标签 @foo
val a = this@A // A 的 this
val b = this@B // B 的 this
val c = this // foo() 的接收者,一个 Int
val c1 = this@foo // foo() 的接收者,一个 Int
val funLit = lambda@ fun String.() {
val d = this // funLit 的接收者
}
val funLit2 = { s: String ->
// foo() 的接收者,因为它包含的 lambda 表达式
// 没有任何接收者
val d1 = this
}
}
}
}
如果 this 没有限定符,它指的是最内层的包含它的作用域。要引用其他作用域中的 this,请使用 标签限定符:
注解
annotation class Fancy
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Inherited
annotation class Action(val name: String="")
注解的附加属性
@Target 指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等);
@Retention 指定该注解是否存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true);
@Repeatable 允许在单个元素上多次使用相同的该注解;
@MustBeDocumented 指定该注解是公有 API 的一部分,并且应该包含在生成的 API 文档中显示的类或方法的签名中。
注解的参数中可指定其他的注解
annotation class ReplaceWith(val expression: String)
annotation class Deprecated(
val message: String,
val replaceWith: ReplaceWith = ReplaceWith(""))
注解的参数中可指定类,使用KClass
import kotlin.reflect.KClass
annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any>)
@Ann(String::class, Int::class) class MyClass
收藏
立即使用
Collect
Get Started
Collect
Get Started
Collect
Get Started
Collect
Get Started
评论
0 条评论
下一页