Kotlin 语法
type
status
date
slug
summary
tags
category
icon
password
仅适合快速掌握过一遍知识
 

基础

函数声明

声明函数要用 fun 关键字,就像声明类要用 class 关键字一样
「函数参数」的「参数类型」是在「参数名」的右边函数的
「返回值」在「函数参数」右边使用:分隔,没有返回值时可以省略
 
声明没有返回值的函数:
 
声明有返回值的参数:
 

变量声明

  • var 可读可写变量
  • val 只读变量
  • 「类型」在「变量量名」的右边,用 : 分割,同时如果满足「类型推断」,类型可以省略创建对象直接调用构造器,不需要new关键字
 

继承类 / 实现接口

继承类 / 实现接口 都是使用 如何类中没有构造器 constructor ,需要在父类类名后面加上 ()
 

空安全设计

Kotlin中的类型设计分为 可空类型 和 不可空类型
 
不可空类型:
 
  可空类型:(有可能为 null, 必须声明)
 

调用符

!!  强行调调用符
?. 安全调用符号 //?表示 判断是不是空,非空才会被调用
 

lateinit 关键字

延迟初始化
lateinit 只能修饰var可读可写变量(思考下为什么) 因为val 只能赋值一次
lateinit 关键字声明的变量的类型必须是「不可空类型」,例如Android的 Edittetx
lateinit 声明的变量不能有「初始值」
lateinit 声明的变量不能是「基本数据类型」,
像Android的 Edittext可以
在构造器中初始化的属性不需要 lateinit 关键字
 
 

类型判断

is 判断属于某类型
!is 判断不属于某类型
as 类型强转,失败时抛出类型强转失败异常
as? 类型强转,但失败时不会抛出异常而是返回null
 
notion image
 

获取 Class 对象

使用类名 ::class 获取的是 Kotlin 的类型是 KClass
使用类名 ::class.java 获取的是 Java 的类型
eg.
 

setter/getter

默认是这代码,不用写的, Kotlin 在声明的时候已将setter 和 getter 关联
notion image
在 Kotlin 声明属性的时候(没有使用private修饰),会自动生成一个私有属性和一对公开的setter/getter函数。
在写setter/getter的时候使用field来代替内部的私有属性(防止递归栈溢出)。
 
为什么EditText.getText()的时候可以简化,但是 EditText.setText() 的时候不能和TextView.setText()一样简化?
 
因为EditText.getText()获得的类型是Editable,对应的如果EditText.setText()传入的参数也是Editable就可以简化了。
 
 
 

类与对象

可见性修饰符:

  • 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
  • 如果你声明为 private,它只会在声明它的文件内可见;
  • 如果你声明为 internal,它会在相同模块内随处可见;
  • protected 不适用于顶层声明。
  • 注意:要使用另一包中可见的顶层声明,仍需将其导入进来。
类和接口
对于类内部声明的成员:
  • private 意味着只在这个类内部(包含其所有成员)可见;
  • protected—— 和 private一样 + 在子类中可见。
  • internal —— 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员;
  • public —— 能见到类声明的任何客户端都可见其 public 成员。
请注意在 Kotlin 中,外部类不能访问内部类的 private 成员。
如果你覆盖一个 protected 成员并且没有显式指定其可见性,该成员还会是 protected 可见性。
例子:
 

构造函数

在一个类中 可以有一个构造函数以及一个或多个次构造函数,主构造函数是类头的一部分,跟在类名(与可选的类型参数)后。
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
如果我们在构造器主动调用了了父类构造,那么在继承类的时候就不能在类的后面加上小括号
 

@JvmField

生成属性通过 @JvmField 注解可以让编译器只生成一个 public 的成员属性,不生成对应的 setter/getter 函数
 

Any 和 Unit

Any Kotlin 的顶层父类是Any,对应 Java 当中的 Object,但是比 Object 少了wait()/notify() 等函数
Unit Kotlin 中的 Unit 对应 Java 中的 void
 

数组

arrayOf() 不可变
val arrayOf = arrayOf(1,2,3,4,5) Kotlin 会进行装箱,消耗内存
会使用 专门的数据类型
val intArray = intArrayof(1,2,3,4,6778)
基本数据类型 和包装类型
 
 

kotlin的静态函数定义(三种方法)

函数和属性都可以定义在文件中)

1.Class 类 中直接定义 (顶层函数 or 包级函数)

notion image
调用的时候不需要导包,这种函数叫做 顶层函数 or 包级函数 ,Java 也可以调用eg.
文件名Kt.dp2px(12f);
UtilsKt.dp2px(12f);
 

2.Object (声明单例对象)

notion image
 
Java中调用:
 

3.companion object 伴生对象

notion image
转为Kotlin 👇
compaion obejct : 维护内部类的一个作用 ,是一个单列,不是静态函数
notion image
notion image
Java 调用: 加上 @JvmStatic 可变为真正的静态
 
Kotlin 为什么会把 static 删掉? 不是更简洁嘛, 但是使用static 声明函数后,这函数就不属于任何对象了 。使用Object 则是加强了这个万物皆对象的概念。
 
Java 1.8 仅支持 字符串,枚举。
Java 12 的 switch 支持表达式了
 
其中,「顶层函数」直接在文件中定义函数和属性,会直接生成静态的,在 Java 中通过「文件名Kt」来访问,同时可以通过 @file:JvmName 注解来修改这个「类名」。
需要注意,这种顶层函数不要声明在 module 内最顶层的包中,至少要在一个包中例如 com 。不然不能方便使用。objectcompanion object 都是生成单例例对象,然后通过单例对象访问函数和属性的。
 
枚举 特殊的class
 
注解 接口
 
List 不可修改
ArrayList, MutableList 可修改集合

标签

在 Java 中通过「类名.this例如Outer.this」获取目标类引用在 Kotlin 中通过「this@类名例如this@Outer」获取目标类引用

内部类

Kotlin 中,内部类默认是静态内部类 。没有关键字,
嵌套内部类 有关键字 inner, 可以被外部访问 ,不能有伴生对象
 
如果想让一个类 在 其他模块中被访问到,但同时又不想让app 模块 访问
Java 不支持,Java 中是 使用 @hide 注解 实现类似功能
Kotlin 模块内访问的修饰符 internal (当前模块可见)
 

注释

注释中可以在任意地方使用[]来引用目标,代替 Java 中的@param@link等。
 

非空断言

可空类型强制类型转换成不可空类型可以通过在变量后面加上!!,来达到类型转换。
 

open / final

Kotlin 中的类和函数,默认是被final修饰的 ( abstract override 例外)
 

编译期常量

什么是编译期常量:编译过后的字节码,所有引用该常量的地方都会直接替换成值,这样有利于提高代码运行效率。
Java 中 同时被 final 修饰:
Kotlin 中:
在静态变量上加上const关键字变成编译期常量
 

 

进阶

 
Kotlin 进阶 2022 0203

主构造器

notion image
成员变了初始化可以直接访问到主构造参数

次级构造

notion image

init代码块

 
notion image
主构造不能包含任何的代码,初始化代码可以放到 init 代码块中 自上而下的顺序执行
 
 
notion image
在初始化的时候,初始化代码会按照
 

构造属性

在主构造函数前面加上 val /var 时构造参数同事成为成员变量
notion image
 

data class

数据类同时会生成
toStirng()
hashCode()
equals()
copy() 浅拷贝
componentN() 解构
 

相等性

== 表示 equal
=== 表示地址比较 有可能是不同的两个对象
 

解构

可以把一个对象「解构」成很多变量
notion image
对应的 Java 代码
notion image
 

Elvis 操作符

可以通过?:的操作来简化if null的操作
?. ?:
eg.
 

when 操作符

when 表达式可以接受返回值,多个分支相同的处理方式可以放在一起,用逗号分隔
notion image
 
when 表达式可以用来取代 if-else-if 链。如果不提供参数,所有的分支条件都是布尔表达式
notion image
 

operator

通过 operator 修饰「特定函数名」的函数,例如plus、get,可以达到重载运算符的效果
表达式
含义
a + b
a.plus(b)
a - b
a.minus(b)
a * b
a.times(b)
a / b
a.div(b)

lambda

如果函数的最后一个参数是 lambda,那么 lambda 表达式可以放在圆括号之外:
 
如果你的函数传入参数只有一个 lambda 的话,那么小括号可以省略的:
 
如果 lambda 表达式只有一个参数,那么可以省略,通过隐式的it来访问循环 lessons.
 

循环

1.标准函数repeat():
2.区间
 

infix 函数

必须是成员函数或者拓展函数
必须只能接受一个参数,并且不能有默认值
 

嵌套函数

Kotlin 可以在函数中继续声明函数
  • 内部函数可以访问外部函数的参数
  • 每次调用时,会产生一个函数对象
 

注解使用处目标

 
函数简化
通过 = 简化 return 的函数
 

函数参数默认值

可以通过函数参数默认值来代替
 

扩展函数

  • 可以为任何类添加上一个函数,用于代替工具类
  • 和成员函数相同时,成员函数优先被调用
  • 是静态解析的,在编译时就确定了调用函数(没有多态)
 

函数类型

函数类型由「传入参数类型」和「返回值类型」组成,用「->」连接,传入参数需要用「()」,如果返回值为 Unit 不能省略函数类型实际是一个接口,我们传递函数的时候可以通过「::函数名」,或者「匿名函数」或者使用「lambda
 

内联函数

  • 内联函数配合函数类型 ,可以减少函数类型生成的对象 (减少调用栈,行数多的话编译时间会增加。)
  • 使用 inline 关键字声明 内联函数,在编译时会将内敛函数中的函数体直接插入到调用处。
在写内联函数的时候需要注意,尽量将内联函数中的代码行数减少!
 

部分禁用内联

noinline 可以禁止部分参数参与内联编译
 
具体化的类型参数
因为内联函数的存在,可以通过配合 inline + reified 达到 「 真泛型 」的效果
 

抽象属性

在 Kotlin 中,可以声明抽象属性, 子类怼抽象属性重写的时候需要重写对应的 setter / getter
 

委托

属性委托
有些常⻅的属性操作,我们可以通过委托的方式,让它只实现一次,例如:
  • lazy 延迟属性:值只在第一次访问的时候计算
  • observable 可观察属性: 属性发生改变时可通知
  • map 集合:将属性存入一个 map中
对于一个只读属性(即 val 声明的),委托对象必须提供一个名为 getValue() 的函数
对于一个可变属性(即 var 声明的),委托对象同时提供 setValue()getValue() 函数
 

类委托

可以通过类委托的模式来减少继承
类委托的,编译器会优先使用自身重写的函数,而不是委托对象的函数
 
Kotlin 标准函数
使用时可以通过简单的规则作出一些判断:
  • 返回自身 → 从 applyalso
    • 作用域中使用 this 作为参数 → apply
      作用域中使用 it 作为参数 → also
  • 不需要返回自身 → 从 runlet 选择
    • 作用域中使用 this 作为参数 ----> run
      作用域中使用 it 作为参数 ----> let
 
apply 适合对一个对象做附加操作的时候,
let 适合配合空判断的时候 (最好是成员变量,而不是局部变量,局部变量更适合用 if )
with 适合对同一个对象进行多次操作的时候

过滤(Filtering)集合

 
 
 
 

© Anne 2021-2024