kotlin 语法简单理解

kotlin 语法

1.变量定义

val 定义常量 相当于 final
var 定义变量 非final类型变量

  //常量 
    val x: Int = 10 //要给默认值
    val x1 = 10 //推断,等同与上边
    //变量
    var y:Int = 10
    var y1 = "hello world"
    
     companion object {
        //public final static I staticVal = 10
        const val staticVal = 10
        
        //private final static I zxy
         val staticVal2 = 100
    }
    

2.逻辑控制

if(num1>num2) num1 else num2

//类似 Java switch
when(var){
  0 -> {}
  1 -> {}
  else -> {}
}
//还可以这样写
when(var){
  is Int -> {}
  is Float -> {}
  else -> {}
}
//或者这样写,比Java要灵活 
 fun test(name: String) = when {
        y1.startsWith("hi") -> {}
        y1.endsWith("world") -> {}
        y1 == "niHao" -> {}
        else -> {}
 }

常用的循环

for (i in 0..10){}
for (i in list){}
for (i in 0..list.size)
for (i in 0 until 100 step 2){}
for (i in 10 downTo 1) //倒序
for ((index, entry) in list.withIndex())

list.forEach {  }
for ((key, value) in map)

其他一些有用的内置函数 list.map{} list.maxBy{} list.filter{}

3.集合

实例化:

val list = ArrayList() //类似Java 写法
val list = listOf(0,1,2,3)//不可变,不可add remove
val list = mutableListOf<Int>() //可变
//同样的还有
val map = mapOf(1 to 1, 2 to 2,3 to "3")
val map = mutableMapOf<Int,Int>()
val array =  arrayOf(0, 1, 2)//长度不可变,值可变
val array = arrayListOf<Int>()
val array = IntArray(3)
//多维数组
val array2d = Array(3,{Array(3){it -> 0}})

4.类:继承/构造函数

  1. Kotlin中类与Java类没什么太大差别
    class HelloWorld{}
  2. Kotlin 中继承省去extends、implements 关键字
    class Student: Person(), Interface{}
    但是一个类必须加上open才可以被继承
  3. Kotlin 中主构造函数
    主构造函数:
    1.默认不带参数的构造函数,也可以显式给添加参数;
    2.特点就是没有函数体, 可在init{}做初始化操作;
    3.在类名的后边;
    4.要调用父类的构造函数;
class Student: Person(){
    init{
        //do something
    }
}
  1. Kotlin 中次构造函数
    1.constructor()
    2.有函数体
    3.必须调用主构造(或者间接调用)
class Other() : Fat() {
    constructor(x:Int): this(){}
}
//间接调用
class Other() : Fat() {
    constructor(x:Int): this(){}
    constructor(x:Int, y:String): this(x){}
}

类可以没有主构造函数但是需调用父构造函数

class Other :Fat{
    constructor():super(){}
}

自定义View可以这么写,避免重写多个构造

class CustomView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
}

5.运算符

运算符 Java Kotlin
& and
or
~ inv
抑或 ^ xor
左移 << shl
右移 >> shr
其他 equals() ==
其他 == ===

6.可见性修饰符

修饰符 Java Kotlin
public 所有类可见 所有类可见(默认)
private 当前类可见 当前类可见
protected 当前类、子类、同包可见 当前类、子类
default 同包内可见(默认)
internal 同意模块类可见

7.数据类/单例类/密封类

  • 数据类
data class HelloWorld(var v1 = 1,val v2: Int)//默认参数

比Java 省去了 equals()/hashCode()/toString() 。

  • 单例类
    object HelloWorld{}
    该类内部方法可通过类名.方法名调用,但类内部的方法并非是静态方法,如果要定义静态方法需要定义注解或是定义成顶层方法。
  • 密封类
    主要配合when() 使用 ,优化else分支。
sealed class Action
class Cry: Action() 
class Run:Action()
class Eat:Action()

fun doSomething(action:Action) = when(action) {
    is Cry -> {}
    is Run -> {}
    is Eat -> {}
}

8.标准函数

Kotlin 提供了一些标准函数在Standard.kt 文件中定义

  1. with
    用法 with(var1){} ,返回最后一行 (block()函数)
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}
  1. apply list.apply{},返回调用者本身
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
  1. let x.let{} , 返回最后一行
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
  1. 其他的可以查看函数一下该文件(also、run等)

9.扩展函数

可以直接给已定义的类(比如系统类)添加函数;

fun String.getNumberCount():Int{
    var num = 0
    for(c in this){
        if(c is Char) num++
    }
    return num
}

//可以直接调用
val num = "iuqwe189123hqwwqe".getNumberCount()

10.运算符重载

在Java 中经常见到字符串相加

String h = "hello" + "world";

但是在kotlin中,对象也可以相加

class Student(val score:Int){

    operator fun plus(that: Student): Student{
        return Student(this.score + that.score)
    }
}

//使用
val s1 = Student(70)
val s2 = Student(80)
val s3 = s1 + s2

类似的方法还有
minus(-) 、 times(*)、div(/)、rem(%) 其他
可在Primitives.kt 查看

11.高阶函数

语法:函数内接收一个函数类型参数

fun example(func: (String, Int) -> Unit){
}

因此可以自定义一些高级功能:

fun StringBuilder.build(block: StringBuilder.() -> Unit):StringBuilder {
    block()
    return this
}

其实就是类似标准函数中apply 写法
然后就可以这么用

val sb = StringBulider().build{
    append("hello") 
    append("\u2000") 
    append("world")
}

内联函数
上边函数其实是在build函数中创建了匿名内部类,每次调用都会创建一个Function匿名内部类来替换内部的block 方法。为了消除性能开销kotlin 提供了inline 关键字。

inline fun StringBuilder.build(block: StringBuilder.() -> Unit):StringBuilder {
    block()
    return this
}

这个关键字的作用就是,直接将block的方法体替换到build方法内部,代码解释就是:

inline fun test(num1:Int, num2: Int, block: (Int, Int)): Int{
    return 
}
//调用
val x = test(10, 20){
    10 + 20 
}
//加上inline 相当于
fun test(num1:Int, num2: Int): Int{
    return num1 + num2// block()
}     

还有一点就是inline 修饰的高阶函数,block 函数内部可以直接return ,并且会直接结束掉该方法,而非内联函数则只能局部返回,代码可能比较直观:

fun printString(bool: Boolean,block: (Boolean)-> Unit){
    println("start")
    block(bool)
    println("end")
}
//调用
 println("main start")
 printString(true){
     println("block start")
     if (it) return@printString
     println("block end")
 }
 println("main end")
//打印
I/System.out: main start
I/System.out: block start
I/System.out: main end

//加上inline
inline fun printString(bool: Boolean,block: (Boolean)-> Unit){
    println("start")
    block(bool)
    println("end")
}
//调用
println("main start")
printString(true){
    println("block start")
    if (it) return
    println("block end")
}
println("main end")
//打印
I/System.out: main start
I/System.out: block start

inline 相关的还有 noinline 、 crossinline
noinline 与inline 顾名思义就是对立的关系,那oninline 又有什么意义呢?往下看,使用方法:

inline fun printString(block1:()->Unit, noinline block2:() ->Unit){
    block1()
    block2()
}

noinline 其实是结合inline 使用的,当参数有多个函数类型参数时,想要指定某个参数不内联就在其参数前加上noinline关键字,但是还是没有搞懂存在的意义,noinline 作用其实是就是可以把非内联函数类型参数传递给任何其他函数,而内联函数则只能传递给另外一个内联函数,不过平时用的可能不太多。
crossinline又是什么含义?

12.泛型

1.基本用法和Java差不多

class Hello<T>{
    fun method(par: T){
    }
}

class Hello{
    fun <T> method(param: T){
    }
}

//指定上界, 只能传数字类型
class Hello{
    fun <T: Number> method(param: T){
    }
}

默认kotlin 泛型都是可空的因为,默认的上界是Any?,
如果想改成非空的,可以指定上界为Any 或想要的类型。

2.泛型实例化
意思就是可以将一个泛型参数实例化,就可以直接调用其方法,这是Java 所不具备的;
必要条件 inline 修饰的方法且 reified 在泛型前。
定义代码如下:

inline fun <reified T> getType()=T::class.java

有什么作用呢?
看下边代码:

val intent = Intent(context, OtherActivity::class.java)
intent.putExtra("key", "value")
startActivity(intent)

//这是常规写法,这是用泛型实例化优化后
inline fun <reified T> startActivity(context: Context, block: Intent.() -> Unit){
    val intent = Intent(this, T::class.java)
    intent.block()
    context.startActivity(intent)
}

//使用
startActivity<MainActivity>(this){
   putExtra("key", "value")
}

定义成工具方法可见,代码简洁了不少。

3.协变和逆变
协变out,泛型只允许出现在返回值

class Hello<out T>{
    fun method(): T{
    }
}

逆变in,泛型只允许出现在参数中

class Hello<in T>{
    fun method(param: T){
    }
}

13.语法糖infix

1.不能定义成顶层函数;
2.有且只能有一个参数;

infix fun String.add(str: String):Boolean{
   return str.length> temp.length 
}


"hello" add "world"

14.委托

1.类委托
含义就是将实现交给另外一个类来实现;
定义一个自己的List 类

class MyList<T>(val list:List<T>) : List<T>{

    override fun add(t: T) = list.add(t)
    
    override fun remove(t: T) = list.remove(t)
    
    //... 省略其他方法
}

这个类有什么意义?
其实在这个类中可以加入自己定义的方法,其他的方法又委托类来实现,但是这在Java 中可能是很搞笑的做法,因为List 接口所有方法都要手动调用;
但是Kotlin 提供了by 关键字,所以上边代码可以改为

class MyList<T>(val list:List<T>) : List<T> by list{

    override fun contains(t: T) = false    
    
    fun testMethod1(){} 
    fun testMethod2(){} 
    fun testMethod3(){} 
    fun testMethod4(){} 
 }

2.属性委托
委托属性的思想就是把一个属性交给另外一个类来完成。
如何理解:


class Hello{
    val p by Delegate()
}

class Delegate {
    private var _value: Any? = null
    
    operator fun getValue(other: Other, property: KProperty<*>): Any? {
       return _value
    }

    operator fun setValue(other: Other, property: KProperty<*>, any: Any?) {
        _value = any
    }

}

此时p 的set get 就交给Delegate#setValue Delegate#getValue 方法来实现

具体又是如何应用呢?最常见就是val p by lazy{}
可以通过前边代码来懒加载p属性, lazy 是kotlin的一个高阶函数:

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

lazy 会创建一个SynchronizedLazyImpl 对象,当调用get时,是执行了SynchronizedLazyImpl#getValue ,getValue接收一个Lambda表达式,返回该表达式最后一行代码。

private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
    private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    // final field is required to enable safe publication of constructed instance
    private val lock = lock ?: this

    override val value: T
        get() {
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return _v1 as T
            }

            return synchronized(lock) {
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {
                    val typedValue = initializer!!()
                    _value = typedValue
                    initializer = null
                    typedValue
                }
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}

有兴趣或是有需要的话,可以参照实现自己的委托类。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • 一、类 1.1 类声明 Kotin中使用关键字class声明类,且默认是public。如果一个类没有类体,可以省略...
    者文_阅读 1,292评论 0 1
  • 自从实习结束后直到现在将近一年多的时间再也没有用过kotlin, 在今年五月份I/O大会上,Google再次明确了...
    Scus阅读 1,372评论 0 0
  • 最近在学kotlin,这是本人看菜鸟教程后所做的笔记,很多会内容和菜鸟教程重复,仅供参考 基础语法 包声明 函数定...
    Jack921阅读 574评论 0 4
  • kotlin的基础语法 函数定义 函数定义使用关键字 fun,参数格式为:参数 : 类型 可变长参数函数 函数的变...
    不怕天黑_0819阅读 8,593评论 0 5
  • 本文需要读者对协程有基础的了解,关于协程的使用,可以参考官方教程:[play.kotlinlang.org/han...
    我爱田Hebe阅读 370评论 0 1