继承类和实现接口都是用的 : ,如果类中没有构造器 ( constructor ),需要在父类类名后面加上 () :
class MainActivity : BaseActivity(), View.OnClickListener
class User {
?? ?constructor()
}
如果我们在构造器主动调用了父类构造,那么在继承类的时候就不能在类的后面加上小括号
constructor(context: Context) : this(context, null)
// 主动调用了父类的构造器
constructor(context: Context, attr: AttributeSet?) :?super(context, attr)
class CodeView : TextView {
constructor(context: Context): super(context)
}
等价:
class CodeView(context: Context) : TextView(context) {
}
其中,「顶层函数」直接在文件中定义函数和属性,会直接生成静态的,在 Java 中通过「文件名Kt」来 访问,同时可以通过 @file:JvmName 注解来修改这个「类名」。
需要注意,这种顶层函数不要声明在 module 内最顶层的包中,至少要在一个包中例如 com 。不然不能方便使用。
object 和 companion object 都是生成单例对象,然后通过单例对象访问函数和属性的。
// 单例
object Singleton {
}
// 匿名内部类
object : OnClickListener {
}
val number = 100
val text = "向你转账${number}元。"
// 如果只是单一的变量,可以省略掉 {}
val text2 = "向你转账$number元。"
val s = """
?? ?我是第一行
?? ?我是第?行
?? ?我是第三行
?? ?""".trimIndent()
// 声明抽象类
abstract class
// 声明接口
interface
// 声明注解
annotation class
// 声明枚举
enum class
记得让 IDE 来帮助生成 for 循环
for(item in items)
class CodeView : TextView {
?? ?constructor(context: Context): super(context)
}
class CodeView constructor(context: Context) : TextView(context)?
// 如果没有被「可见性修饰符」「注解」标注,那么 `constructor` 可以省略
class CodeView(context: Context) : TextView(context)
成员变量初始化可以直接访问到主构造参数
class CodeView constructor(context: Context) : TextView(context) {
?? ?val color = context.getColor(R.color.white)
}
主构造不能包含任何的代码,初始化代码可以放到 init 代码块中
class CodeView constructor(context: Context) : TextView(context) {
?? ?init {
?? ??? ?//...
?? ?}
}
在初始化的时候,初始化块会按照它们在「文件中出现的顺序」执行。
class CodeView constructor(context: Context) : TextView(context) {
????init {
????????//...
????}
?? ?val paint = Paint() // 会在 init{} 之后运行
}
在主构造参数前面加上 var/val 使构造参数同时成为成员变量
class User constructor(var username: String?, var password: String?, var code: String?)
可以把一个对象「解构」成很多变量
val (code, message, body) = response
对应的 Java 代码
val code = response.component1()
val message = response.component2()
val body = response.component3()
// lesson.date 为空时使用默认值
val date = lesson.date ?:? "日期待定"
// lesson.state 为空时提前返回函数
val state = lesson.state ?:? return
// lesson.content 为空时抛出异常
val content = lesson.content ?: throw IllegalArgumentException("content expected")
val colorRes = when (lesson.state) {
?? ?Lesson.State.PLAYBACK, null -> R.color.playback
?? ?Lesson.State.LIVE -> R.color.live
?? ?Lesson.State.WAIT -> R.color.wait
}
val colorRes = when {
?? ?(lesson.state == Lesson.State.PLAYBACK) ->?R.color.playback
?? ?(lesson.state == null) -> R.color.playback
?? ?(lesson.state == Lesson.State.LIVE) -> R.color.live
?? ?(lesson.state == Lesson.State.WAIT) -> R.color.wait
?? ?else -> R.color.playback
}
如果函数的最后一个参数是 lambda ,那么 lambda 表达式可以放在圆括号之外:
lessons.forEach() { lesson : Lesson ->
?? ?// ...
}
如果你的函数传入参数只有一个 lambda 的话,那么小括号也可以省略的:
lessons.forEach { lesson : Lesson ->
?? ?// ...
}
如果 lambda 表达式只有一个参数,那么可以省略,通过隐式的 it 来访问:
lessons.forEach { // it
?? ?// ...
}
通过标准函数 repeat() :
repeat(100) {
?? ?//..
}
通过区间:
for (i in 0..99) {
}
// until 不包括右边界
for (i in 0 until 100) {
}
// until() 函数的源码
public infix fun Int.until(to: Int): IntRange {
?? ?if (to <= Int.MIN_VALUE) return IntRange.EMPTY
?? ?return this .. (to - 1).toInt()
}
Kotlin 中可以在函数中继续声明函数
fun func(){
?? ?fun innerFunc(){
?? ?}
}
可以通过符号 = 简化原本直接 return 的函数
fun get(key :String) = SP.getString(key,null)
可以通过函数参数默认值来代替 Java 的函数重载
// 使用 @JvmOverloads 对 Java 暴露重载函数
@JvmOverloads
fun toast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
?? ?Toast.makeText(this, text, duration).show()
}
inline fun foo(inlined: () -> Unit, noinline notInlined:() -> Unit) {
?? ?//......
}
val RETROFIT = Retrofit.Builder()
?? ?.baseUrl("https://api.github.com/")
?? ?.build()
inline fun <reified T> create(): T {
?? ?return RETROFIT.create(T::class.java)
}
val api = create<API>()
对于一个只读属性(即 val 声明的),委托对象必须提供一个名为 getValue() 的函数
对于一个可变属性(即 var?声明的),委托对象同时提供?setValue() 、 getValue() 函数
interface Base {
?? ?fun print()
}
class BaseImpl(val x: Int) : Base {
?? ?override fun print() {
?? ??? ?print(x)
?? ?}
}
// Derived 的 print 实现会通过构造参数中的 b 对象来完成。
class Derived(b: Base) : Base by b
使用时可以通过简单的规则作出一些判断:
apply 适合对一个对象做附加操作的时候
let 适合配合判空的时候 (最好是成员变量,而不是局部变量,局部变量更适合用 if )
with 适合对同一个对象进行多次操作的时候