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() //可变
//同样的还有
val map = mapOf(1 to 1, 2 to 2,3 to "3")
val map = mutableMapOf()
val array =  arrayOf(0, 1, 2)//长度不可变,值可变
val array = arrayListOf()
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  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.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.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{
    fun method(par: T){
    }
}

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

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

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

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

inline fun  getType()=T::class.java

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

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

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

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

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

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

class Hello{
    fun method(): T{
    }
}

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

class Hello{
    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(val list:List) : List{

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

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

class MyList(val list:List) : List 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  lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer)

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

private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, 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)
}

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

你可能感兴趣的:(kotlin 语法简单理解)