Kotlin语法简记

版权声明:博文网络共享,尊重知识原创。 https://blog.csdn.net/binglumeng/article/details/79123434

Kotlin语法简记

一、基础语法

  1. 包声明

    Kotlin语言的源文件,不需要对应匹配文件目录和包。

    默认包名default,都会默认导入kotlin下的相关必须包

    //包名中如果含有,kotlin 的关键字,则需要用 反引号 ` 来包装一下
    package `in`.zhiwei.aqi
  2. 函数定义

    fun关键字,格式为args:type,返回类型

    //
    fun sum(a:Int,b:Int):Int{
     return a+b
    }

    若使用lambad类的表达式,返回类型会自动推断。但:public的函数,必须注明返回类型

    fun sum(a:Int,b:Int) = a+b //此时会自动推断返回类型
    
    public fun sum(a:Int,b:Int):Int = a+b //public函数,必须注明返回类型

    Unit无返回类型,类似于Java中的Void

    fun printSum(a:Int,b:Int):Unit{
     print(a+b)
    }
    //Unit类型,可以省略,public函数,也可以。

    vararg可变参数

    fun vars(vararg v:Int){
     for(vt in v){
       print(vt)
     }
    }
    //调用vars函数
    fun main(args:Array<String>){
     vars(1,2,3,4,5)
    }

    lambda匿名函数

    fun main(args:Array<String>){
     val sumLambda:(Int,Int)-> Int = {x,y -> x+y}
     println(sumLambda(1,2))
    }
  3. 常量、变量

    定义变量,常量,使用varval关键字,格式var/val name : Type = value,其中Type可以省略,自动推算

    fun main(args:Array<String>){
     var abc:Int = 3
     val PI = 3.1415926
     println(PI)
     println(abc)
    }
  4. 注释

    kotlin注释,单行 //,多行/* text */且可以嵌套。

  5. 字符串模板

    $符号

    • $表示变量名、或变量值
    • $varName表示变量值
    • ${varName.fun()}表示返回值
    var a = 1
    //变量值
    val s1 = "a is $a"
    a = 2
    //返回值
    val s2 = "${s1.replace("is","was")},but now is $a"
  6. NULL检查机制

    Kotlin的NULL检查,两种:

    • !!符号,抛出异常
    • ?符号,不处理,返回值为null。或者?:三目运算
    //当引用可能为null时候,类型声明必须标记可为null
    //下面示例,str内容若非整数,则会null,所以返回类型必须声明可为null
    fun parseInt(str:String):Int?{
     //....
    }
  7. 类型转换

    使用is!is

    fun getStringLenght(obj:Any):Int?{
     if(obj is String){
       //类型判断后,会自动转换
       return obj.length
     }
     // !is表示,不是某个类型
     return null
    }
  8. 区间

    区间表达式,..的rangeTo,配合in!in。注意范围,数学中的左右闭区间[1,4]

    for (i in 1..4) print(i) // output "1234"
    for (i in 4..1) print(i) // output nothing
    //指定步长
    for (i in 1..4 step 2) print(i)// output "13"
    for (i in 4 downTo 1 step 2) print(i) // output "42"
    //使用until函数,排除结束的那个元素
    for(i in 1 until 10){//[1,10)
     print(i)
    }

二、基础数据类型

类型 位宽度
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

- 字面常量

  • 十进制:123
  • 长整形:123L
  • 16进制:0x0F
  • 2进制:0b00001011
  • 注:不支持八进制
  • Doubles:123.5,123.5e10
  • Floats:123.5f 或123.5F

kotlin
//可以使用下划线,分隔数字,便宜阅读
val oneMillion = 1_000_000
val hexBytes = 0xFF_EC_DE_5E

  • 数字比较

    在上面可以看出,Kotlin都是Double、Int、Float等封装后的类型,没有基础的数据类型,避免空指针。

    • ===对比地址
    • ==对比值
    for main(args:Array<String>){
    val a = 100
    print(a===a)//true,自身对比,值与地址皆同
    //包装
    val boxA:Int? = a
    val boxB:Int? = a
    //对比
    print(boxA == boxB)//true 值相等
    print(boxA === boxB)//false 对象不同,地址不同
    }
  • 类型转换

    不同于Java的小到大可以自动转换,Kotlin不可以。

    val b:Byte = 1
    val i:Int = b //这就错了,b是Byte,不能转化为Int,他们都是包装后的
    val l = 1L + 3 //Int和Long这类还可以自动转
    //其他可以使用toByte,toInt等
  • 位操作符

    适用于Int和Long

    shl(bits) - 左位移(Java中的<<)
    shr(bits) - 右位移(Java中的>>)
    ushr(bits) - 无符号右位移(Java中的>>>)
    and(bits) - &
    or(bits) - |
    xor(bits) - ^
    inv() - reverse
  • 字符

    Kotlin中Char不可与数字直接操作,必须'char'单引号包裹

    c == '1'//不能写作 c == 1
    //特殊字符可以转义,或者Unicode表示
  • Boolean

    ||、&&、!

  • Array

    //[1,2,3]
    val arrA = arrayOf(1,2,3)
    val arrB = Array(3,{i -> (i*2)})

    Kotlin中,数组是不变的类型

  • 字符串String

    • 可以"""三对双引号,来多行
    • for遍历某个字符
    • trimMargin()来删除空白
    val text = """
    |第一行
    |第二行
    |第三行
    """
    //默认使用`|`作为边界前缀,也可以自定义
    trimMargin(">")

三、条件控制

  • if表达式

    var max = a
    if(a<b){
    max = b
    }else{
    max = a
    }
    //或者,类似Java中的三目运算符
    var max = if(a<b) a else b
  • 使用区间

    //x..y
    var a = 7
    if(x in 1..9) print("a in this range")
  • when

    类似其他编程语言中的Swith...case

    when(x){
    1-> print("x == 1")
    2-> print("x == 2")
    3,4-> print("x == 3 or 4")
    in 5..9-> print("x is in this range")//还有!inis ,!is
    in validNumbers-> print("x is valid")
    else-> print("x not 1 or 2")//类似defalut
    }

四、循环控制

  • for循环

    for(item in collection) print(item)
    for(i in array.indices) print(array[i])
    for((index,value) in array.withIndex()) {
    print("item $index is $value")
    }
  • while,do…while

  • return、break、continue

    //Break和Continue 可以配合label标签,确定其作用范围,格式label@
    loop@ for(i in 1..100){
    for(j in 1..100){
      if(...) break@loop
    }
    }
    //return 返回,也可以用label标签确定范围
    fun foo(){
    ints.forEach{
     if(it == 0)return//这么return,就return了真个foo函数
     print(it)
    }
    }
    //配合lable
    fun foo(){
    ints.forEach lit@{
      if(it == 0)return@lit//如此,只return出forEach,
      print(it)
    }
    }
    //可以不用显示声明label,
    fun foo(){
    ints.forEach{
      if(it == 0)return@forEach//隐式label的使用
      print(it)
    }
    }
    //也可以,将lambad中声明匿名函数,return就会在它的范围内return
    fun foo(){
    ints.forEach(fun(value:Int)){
      if(it==0)return
      print(it)
    }
    }
    //return带有返回值的时候,带有label的return,优先
    return@abc 1//从标签abc那里,返回出去数值 1

五、类和对象

//定义类
class Demo{
  var name:String = "Joe"
  var url:String = "www.zhiwei.in"
  val PI = 3.1415926
  //成员函数
  fun foo(){
    print("Foo")
  }
}
//空类
class Empty
//实例化
val demo = Demo()//kotlin 中没有new
demo.name
//构造函数,一个主的,可有多个次的,主构造函数,就在class标题处
class Person constructor(firstName:String){
  //...
}
//若主构造函数,方法体为空,则constructor可以省略
class Person(firstName:String){}

//geter setter 可选
var lastName:String = "Green"
    get()=field.toUpperCase()
    set
var no:Int = 100
    get() = field
    set(value){
    ...
    }
var height:Float = 175.0f
    private set
//field关键字,用于后端变量,kotlin中不能有字段
//非空属性必须定义时候就初始化,kotlin使用lateinit来延迟初始化
public class MyTest{
  lateinit var subject:TestSubject

  @SetUp fun setup(){
    subject = TestSubject()
  }
  @Test fun test(){
    subject.method()
  }
}
  • 主构造器

    不能包含任何代码,需要在init中初始化

class Person constructor(firstName:String){
  init{
    //...
  }
}
//类的参数,可以在构造函数中
class People(val firstName:String, val lastName:String){
  //...
}
  • 次构造函数

    class Person{
    //如果没有主构造函数,则每个次构造函数,可能需要依次调用代理
    //类似与Java中的多个构造函数,内部依次调用
    constructor(parent:Person){
      parent.children.add(this)
    }
    }
    //没有显式的声明构造函数的话,会有一个默认的public的构造函数,类似于Java
  • 抽象类

    abstract关键字

    //可继承
    open class Base{
    open fun f(){}
    }
    abstract class Sub:Base{
    override abstract fun f()
    }
  • 嵌套类

    class Outer{
    private val bar:Int = 1
    class Nested{
      fun foo() = 2
    }
    }
    //调用嵌套
    fun main(args:Array<String>){
    val demo = Outer.Nested().foo()//调用格式,Outer.Nested().foo()
    println(demo)
    }
  • 内部类

    inner关键字

    //内部类会拥有外部类的引用,不同于嵌套类
    class Outer{
    private val bar:Int = 1
    var v = "member property"
    inner class Inner{
      fun foo() = bar
      fun innerTest(){
        var o = this@Outer
        println("持有外部引用:"+o.v)
      }
    }
    }
    //调用
    fun main(args:Array<String>){
    val demo = Outer().Inner().foo()//格式,与嵌套类,略有不同
    println(demo)
    }
  • 匿名内部类

    class Test{
    var v = "abc"
    fun setInterFace(test:TestInterFace){
      test.test()
    }
    }
    //interface
    interface TestInterFace{
    fun test()
    }
    //调用
    fun main(args:Array<String>){
    var test = Test()
    //匿名内部类
    test.setInterFace(obj:TestInterFace{
      override fun test(){
        //...
      }
    })
    }
  • 类的修饰符

    • 属性修饰符
symbol description
abstract 抽象
final 不可继承,kotlin的类,默认都是final
enum 枚举
open 可继承
annotation 注解类

- 权限修饰符

symbol description
private 私有,同一文件内可见
protect 同一文件内,或子类 可见
public 公开
internal 同一模块中可见

六、继承

kotlin中所有类的继承,都是Any类,类似于Java中的Object

//Any类中含有以下三个函数
equals()
  hashCode()
  toString()
//open声明可被继承
open class Base(p:Int)
class Sub(p:Int):Base(p:Int)
  • 继承的构造函数
class Student:Person{
  //子类没有主构造函数,则需要在次构造函数中,super父类的构造函数
  constructor(ctx:Context):super(ctx){}
}
//若是子类有主构造函数,基类也应一致,且在子类继承时候,初始化
open class Person(var name:String,var age:Int){}
//此处,:Person被初始化了name,age
class Student(name:String,age:Int):Person(name,age){
  //...
}
  • 重写函数,属性

基类函数,默认final,需要open的方可重写,重写用override标记

若继承的基类,或接口中,多个基类或接口含有相同函数,则需要复写,且显示super.fun() 调用

属性的重写

open class Foo{
  open val x:Int get{...}
}
class Bar:Foo(){
  override val x : Int = ...
}
//属性的重写,需要兼容,var可以重写val,但是val不能重写var
//可以在构造函数中直接声明 重写
interface Foo{
  val count:Int
}
class Bar1(override val count:Int):Foo
class Bar2:Foo{
  override var count:Int = 0
}

七、接口

类似Java8,interface关键字,可有默认实现

interface MyInterface{
  fun bar()
  fun foo(){
    println("foo")
  }
}
  • 一个类可以实现多个接口

  • 接口的属性,抽象无值,必须复写

    interface MyInterface{
    var name:String
    }
    class MyImpl :MyInterface{
    override var name:String = "Kotlin"
    }

八、扩展

Kotlin支持对类的静态扩展,不需要继承,或者装饰器模式设计

  • 扩展函数
//格式,扩展对象、扩展函数、参数(Nullable)
fun receiverType.functionName(params){
  body
}
//示例:
class User(var name:String)
//新增一个print函数给User类
fun User.Print(){
  print("name:$name")
}
//调用
fun main(args:Array<String>){
  var user = User("kotlin")
  user.Print()//扩展新增的函数
}

静态扩展的,扩展到那个类,就是属于那个类/接口,而不会是它的实现/子类。

  • 属性也可被扩展,但不能初始化。

  • 类内部拥有的其他对象,也可以被扩展

    class MyClass{
    companion object{}//Companion的对象
    }
    fun MyClass.Companion.foo(){
    print("扩展了类的拥有的对象")
    }
  • 扩展作用域

    package foo.bar
    fun Baz.goo(){...}
    //其他包使用
    package com.example.usage
    //import 导入
    import foo.bar.goo
    fun usage(baz:Baz){
    //就能原本不能访问的
    baz.goo()
    }
  • 扩展成员,分发接收者、扩展接收者

    class D{
    fun duck() print("Dark duck")
    }
    class C {
    fun cook()print("Cook food")
    //扩展D的函数
    fun D.ext(){
      duck()//能够调用D的函数
      cook()//也能调用C的函数
    }
    //提供调用扩展函数的方法
    fun callDext(d:D){
      d.ext()//调用扩展函数
    }
    }
    //示例
    fun main(args:Array<String>){
    val c:C = C()//c被称为分发接收者
    val d:D = D()//d被称为扩展接收者
    c.callDext(d)
    }

九、数据类&密封类

kotlin可创建一个只包含数据的类,data关键字

  • 数据类主构造函数,至少一个参数
  • 参数标识val或var
  • 数据类不能abstract、open、sealed或inner
  • 不能继承其他基类,可以多接口实现

附带一些函数equals/hashCode;toString,copy

  • 复制:

    data class User(val name:String, val age:Int)
    
    fun main(args:Array<String>){
    val jack = User(name="Jack",age = 1)
    val olderJack = jack.copy(age = 2)
    print(jack)
    print(olderJack)
    }
    //解构声明
    val jane = User("Jane",27)
    val(name,age) = jane
    println("$name,$age years of age")
    //输出结果:Jane,27 years of age

    标准数据类PairTriple,但是建议自定义数据类使用

  • 密封类

    sealed关键字,用于限定类中的值的类型,而不是任意类型

    密封类可有子类,但必须在其中内嵌

    sealed不能修饰interface、abstract类,会警告,但不会编译错误

sealed class Expr//密封类
data class Const(val number:Double):Expr()//密封类的子类
data class Sum(val e1:Expr,val e2:Expr):Expr()//密封类的子类
object NotANumber:Expr()

fun eval(expr :Expr):Double = when(expr){
  is Const -> expr.number
  is Sum -> eval(expr.e1)+eval(expr.e2)
  NotANumber -> Double.Nan
}

十、泛型

class Box<T>(t:T){
  var value = t
}
//示例,实例化时候,需要具体参数类型
val box:Box<Int> = Box<Int>(1)
//或
val box = Box(1)

//函数
fun <T> boxIn(value:T) = Box(value)
val box2 = boxIn<Int>(1)
val box3 = boxIn(1)//自动推测类型

//可推断的类型,可不申明
fun main(args: Array<String>) {
    val age = 23
    val name = "runoob"
    val bool = true

    doPrintln(age)    // 整型
    doPrintln(name)   // 字符串
    doPrintln(bool)   // 布尔型
}

fun <T> doPrintln(content: T) {
//when内做了类型判断
    when (content) {
        is Int -> println("整型数字为 $content")
        is String -> println("字符串转换为大写:${content.toUpperCase()}")
        else -> println("T 不是整型,也不是字符串")
    }
}

泛型约束,类似于Java中的T extends ABC之类的

fun <T : Comparable<T>> sort(list:List<T>){
  //...
}
//多个上限约束,使用where
fun <T> cloneWhenGreater(list:List<T>,threshold:T):List<T> where T:Comparale,Cloneable{
  //...
}
  • 型变

    kotlin没有通配符,有declaration-site variancetype projections

    • in 消费,入参,非出参
    • out 生产,作为出参,而不能入参(即,返回类型,而非传入类型)
    //定义支持协变的类
    class Test<out A>(val a:A){
    fun foo():A{
      return a
    }
    }
    //
    fun main(args:Array<String>{
    var strCo:Test<String> = Test("a")
    var anyCo:Test<Any> = Test<Any>("b")
    anyCo = strCo
    println(anyCo.foo())//输出结果为 “a”
    }
    //定义一个支持逆变的类
    class Test<in A>(a:A){
    fun foo(a:A){
      //...
    }
    }
    //
    fun main(args:Array<String>){
    var strDCo = Test("a")
    var anyDCo = Test<Any>("b")
    strDCo = anyDCo
    }
  • 星号投射

    Function<*,Sting>,表示Function<in Nothing,String>
    Function<Int,*> ,表示Function<Int,out Any?>
    Function< , > ,表示Function<in Nothing,out Any?>

十一、枚举类

enum class Color{
  RED,BLACK,BLUE,GREEN,YEELOW,WHITE
}
//或
enum class Color(val rgb:Int){
  RED(0xFF0000),
  GREEN(0x00FF00)
}
//匿名内部类形式
enum class ProtocolState{
  WAITING{
    override fun signal() = TALKING
  },
  TALKING{
    override fun signal()= WAITING
  };
  abstract fun signal():ProtocolState
}

枚举中,成员用;分隔

enum class Color{
  RED,BLACK,BLUE,GREEN,WHITE
}
//test
fun main(args: Array<String>) {
    var color:Color=Color.BLUE

    println(Color.values())
    println(Color.valueOf("RED"))
    println(color.name)
    println(color.ordinal)
}

十二、对象表达式&声明

//匿名类对象
window.addMouseListener(obj:MouseAdapter(){
  override fun mouseClicked(e:MouseEvent){
    ...
  }
})
//或继承基类,接口的对象
val ab:A = obj:A(1),B{//A 是基类,B是接口,ab声明一个A类型对象,= 一个A的子类且实现了B接口的对象
  override val y = 15
}
//越过类的定义
fun main(args: Array<String>) {
    val site = object {
        var name: String = "菜鸟教程"
        var url: String = "www.runoob.com"
    }
    println(site.name)
    println(site.url)
}
//构造函数,共有的话,则public,
class C {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函数,所以其返回类型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // 没问题
        val x2 = publicFoo().x  // 错误:未能解析的引用“x”
    }
}

object关键字,声明对象

object Site {
    var url:String = ""
    val name: String = "Google Cloud"
}
fun main(args: Array<String>) {
    var s1 =  Site
    var s2 = Site
    s1.url = "www.google.com"
    println(s1.url)
    println(s2.url)
}
//两个输出,都是同一个url
class Site {
    var name = "google cloud"
    object DeskTop{
        var url = "www.google.com"
        fun showName(){
            print{"desk legs $name"} // 错误,不能访问到外部类的方法和变量
        }
    }
}
fun main(args: Array<String>) {
    var site = Site()
    site.DeskTop.url // 错误,不能通过外部类的实例访问到该对象
    Site.DeskTop.url // 正确
}

类内部的对象声明,可以用companion关键字标记,构成伴生,一个类只有一个伴生对象,即companion只能出现一次

class MyClass{
  companion object Factory{
    fun create():MyClas = MyClass()
  }
}
//access
val instance = MyClass.create()

十三、委托

kotlin直接支持委托模式,即一个类中的方法,调用另一个类的函数实现by关键字

  • 类委托
// 创建接口
interface Base {   
    fun print()
}

// 实现此接口的被委托的类
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

// 通过关键字 by 建立委托类,由Base的实现类,具体操作
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 输出 10
}
  • 属性委托

    某个属性,是由其他类代理实现

    var/val name:Type by 表达式

    • 定义为拖类,包含getValue、setValue函数,thisRef、prop
    // 定义包含属性委托的类
    class Example {
      var p: String by Delegate()
    }
    
    // 委托的类
    class Delegate {
      operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
          return "$thisRef, 这里委托了 ${property.name} 属性"
      }
    
      operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
          println("$thisRef 的 ${property.name} 属性赋值为 $value")
      }
    }
    fun main(args: Array<String>) {
      val e = Example()
      println(e.p)     // 访问该属性,调用 getValue() 函数
    
      e.p = "google kotlin"   // 调用 setValue() 函数
      println(e.p)
    }
  • 标准委托

    • 延迟属性Lazy
    val lazyValue: String by lazy {
        println("computed!")     // 第一次调用输出,第二次调用不执行
        "Hello"
    }
    
    fun main(args: Array<String>) {
        println(lazyValue)   // 第一次执行,执行两次输出表达式
        println(lazyValue)   // 第二次执行,只输出返回值
    }
    • Observable
    class User {
        var name: String by Delegates.observable("初始值") {
            prop, old, new ->
            println("旧值:$old -> 新值:$new")
        }
    }
    
    fun main(args: Array<String>) {
        val user = User()
        user.name = "第一次赋值"
        user.name = "第二次赋值"
    }
    //执行结果
    旧值:初始值 -> 新值:第一次赋值
    旧值:第一次赋值 -> 新值:第二次赋值
    • map 映射
    class Site(val map: Map<String, Any?>) {
        val name: String by map
        val url: String  by map
    }
    
    fun main(args: Array<String>) {
        // 构造函数接受一个映射参数
        val site = Site(mapOf(
            "name" to "Google Cloud",
            "url"  to "www.google.com"
        ))
    
        // 读取映射值
        println(site.name)
        println(site.url)
    }
    //结果
    Google Cloud
    www.google.com
    • Not Null
    class Foo {
        var notNullBar: String by Delegates.notNull<String>()
    }
    //若是不赋值,就print访问,则会抛异常
    foo.notNullBar = "bar"
    println(foo.notNullBar)
    • 局部委托属性

尴尬,粗略的看一遍,真的有点累,以后慢慢充实….

猜你喜欢

转载自blog.csdn.net/binglumeng/article/details/79123434