• Kotlin 语言学习


    写在前面

    本文更偏向于有一定java基础的人学习,主要区分Kotlin 语言和java的区别。

    当然,没有java基础您也可以学习Kotlin,请跳转 :Kotlin 零基础入门

    如果不想配置Kotlin环境:Kotlin在线编程

    1、关于Kotlin

    Kotlin 可以编译成Java字节码,也可以编译成 JavaScript。
    Kotlin 程序文件以 .kt 结尾,如:hello.kt 、app.kt。
    Kotlin 命令行编译工具下载地址:Kotlin v1.1.2

    2、基本语法

    2.1、类、方法、变量

    1、行末分号可以省略,
    2、变量、参数、方法返回的类型写在冒号后面,
    3、创建对象不用new,
    4、注释和java一样,
    5、$p拼接字符串。

    package hello                                  //  可选的包头
     
    fun main(args: Array<String>) {                // 包级可见的函数,args 参数,Array 参数类型
       println("Hello World!")
       val s = "字符串"
       val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
       println(str)
    
    	val price = "${'$'}9.99"
        println(price)  // 结果为 $9.99
    }
    
    fun sum(a: Int, b: Int): Int {                  // Int 参数,返回值 Int
        return a + b
    }
    
    public fun sum(a: Int, b: Int): Int = a + b     // public 方法则必须明确写出返回类型
    
    class Greeter(val name: String) {
       fun greet() { 
          println("Hello, $name")                   // 用$拼接字符串
       }
    }
    
    fun gg(): Unit {                               // Unit 无返回值,相当于void,也可以省略
        Greeter("World!").greet()                  // 创建一个对象不用 new 关键字
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.2、var 、val 、vararg

    var 可修改变量、val 不可修改变量

    val a: Int = 1
    val b = 1       // 系统自动推断变量类型为Int
    val c: Int      // 如果不在声明时初始化则必须提供变量类型
    c = 1           // 明确赋值
    
    
    var x = 5        // 系统自动推断变量类型为Int
    x += 1           // 变量可修改
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    vararg 可变产长参数

    fun vars(vararg v:Int){
        for(vt in v){
            print(vt)
        }
    }
    
    fun main(args: Array<String>) {
        vars(1,2,3,4,5)  // 输出12345
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.3、匿名函数

    fun main(args: Array<String>) {
        val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
        println(sumLambda(1,2))  // 输出 3
    }
    
    • 1
    • 2
    • 3
    • 4

    2.4、NULL检查机制

    //类型后面加?表示可为空
    var age: String? = "23" 
    //抛出空指针异常
    val ages = age!!.toInt()
    //不做处理返回 null
    val ages1 = age?.toInt()
    //age为空返回-1
    val ages2 = age?.toInt() ?: -1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。
    当 str 中的字符串内容不是一个整数时, 返回 null

    fun parseInt(str: String): Int? {
    	return str.toIntOrNull()
    }
    
    • 1
    • 2
    • 3

    2.5、类型判断

    fun getStringLength(obj: Any): Int? {
      if (obj is String) {                                          // 单行if,{}可以省略
        // 做过类型判断以后,obj会被系统自动转换为String类型
        return obj.length 
      }
    
      //在这里还有一种方法,与Java中instanceof不同,使用!is
      // if (obj !is String){
      //   // XXX
      // }
    
      // 这里的obj仍然是Any类型的引用
      return null
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.6、数据类型

    Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是,字符不属于数值类型,是一个独立的数据类型。

    字面量:
    1、长整型以大写的 L 结尾:123L
    2、16 进制以 0x 开头:0x0F
    3、2 进制以 0b 开头:0b00001011
    4、注意:8进制不支持

    5、Doubles 默认写法: 123.5, 123.5e10
    6、Floats 使用 f 或者 F 后缀:123.5f
    7、数字中可以使用下划线,使数字更易读

    val hexBytes = 0xFF_EC_DE_5E
    val bytes = 0b11010010_01101001_10010100_10010010
    
    • 1
    • 2

    在 Kotlin 中,三个等号, 表示比较对象地址,两个等号表示比较两个值大小
    Byte、Short、Int等这些基本类型也有对象地址。

    println(a === a) // true,值相等,对象地址相等
    
    • 1

    toByte()、toShort()、toInt()、toLong()等方法用于类型间转换。

    val b: Byte = 1
    val i: Int = b.toInt()
    
    • 1
    • 2

    Char 不能直接和数字操作,Char 必需是单引号 ’ 包含起来

    fun check(c: Char) {
    	println(c == 1)                 // false
    	println(c == '1')               // true
    }
    
    • 1
    • 2
    • 3
    • 4

    多行字符串可以用三个引号

    fun main(args: Array<String>) {
        val text = """
        |第一行
        |第二行
        |第三行
        |第四行
        """.trimMargin()         //  trimMargin() 方法删除多余的空白
        println(text)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.7、异常

    fun decimalDigitValue(c: Char): Int {
        if (c !in '0'..'9')
            throw IllegalArgumentException("Out of range")
        return c.toInt() - '0'.toInt()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.8、数组

    fun main(args: Array<String>) {
        //[1,2,3]
        val a = arrayOf(1, 2, 3)
        //[0,2,4]
        val b = Array(3, { i -> (i * 2) })
    
        //读取数组内容
        println(a[0])    // 输出结果:1
        println(b[1])    // 输出结果:2
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.9、条件控制

    var max: Int
    if (a > b) {
        max = a
    } else {
        max = b
    }
     
    // 作为表达式
    val max = if (a > b) a else b
    
    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    when类似 switch

    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块
            print("x 不是 1 ,也不是 2")
        }
    }
    
    
    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    
    
    when (x) {
        in 1..10 -> print("x is in the range")
        in validNumbers -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
    
    fun hasPrefix(x: Any) = when(x) {
        is String -> x.startsWith("prefix")
        else -> false
    }
    
    
    when {
        x.isOdd() -> print("x is odd")
        x.isEven() -> print("x is even")
        else -> print("x is funny")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    for循环

    // 迭代器
    for (item in collection) print(item)
    
    for (item: Int in ints) {
        // ……
    }
    
    // list
    for (i in array.indices) {
        print(array[i])
    }
    
    fun main(args: Array<String>) {
        val items = listOf("apple", "banana", "kiwi")
        for (item in items) {
            println(item)
        }
    
        for (index in items.indices) {
            println("item at $index is ${items[index]}")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在循环中 Kotlin 支持传统的 break 和 continue 操作符。
    return 允许我们从外层函数返回,
    从 lambda 表达式中返回,我们必须给它加标签并用以限制 return。

    // return结束整个foo
    fun foo() {
        ints.forEach {
            if (it == 0) return
            print(it)
        }
    }
    
    // return结束forEach
    fun foo() {
        ints.forEach lit@ {
            if (it == 0) return@lit
            print(it)
        }
    }
    
    // 函数名也是一个标签
    fun foo() {
        ints.forEach {
            if (it == 0) return@forEach
            print(it)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    当要返一个回值的时候,解析器优先选用标签限制的 return

    return@a 1
    
    • 1

    2.10、类

    class Baidu {
        var name: String = "百度"
        var url: String = "www.baidu.com"
        var city: String = "北京"
    }
    
    val site = Runoob()
    println(site.name)
    
    // constructor主构造器,这个关键字可以省略
    class Person constructor(firstName: String) {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    getter 和 setter 都是可选

    var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
    var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
    val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
    val inferredType = 1   // 类型为 Int 类型,默认实现 getter
    
    • 1
    • 2
    • 3
    • 4

    实例

    class Person {
    
        var lastName: String = "zhang"
            get() = field.toUpperCase()   // 将变量赋值后转换为大写
            set
    
        var no: Int = 100
            get() = field                // 后端变量
            set(value) {
                if (value < 10) {       // 如果传入的值小于 10 返回该值
                    field = value
                } else {
                    field = -1         // 如果传入的值大于等于 10 返回 -1
                }
            }
    
        var heiht: Float = 145.4f
            private set
    }
    
    // 测试
    fun main(args: Array<String>) {
        var person: Person = Person()
    
        person.lastName = "wang"
    
        println("lastName:${person.lastName}")
    
        person.no = 9
        println("no:${person.no}")
    
        person.no = 20
        println("no:${person.no}")
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    field 后端变量
    field 关键词只能用于属性的访问器

    var no: Int = 100
            get() = field                // 后端变量
            set(value) {
                if (value < 10) {       // 如果传入的值小于 10 返回该值
                    field = value
                } else {
                    field = -1         // 如果传入的值大于等于 10 返回 -1
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    init 关键字初始化代码段

    class Person constructor(firstName: String) {
        init {
            println("FirstName is $firstName")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二级构造函数

    class Person { 
        constructor(parent: Person) {
            parent.children.add(this) 
        }
    }
    
    // this调用主构造函数的name
    class Person(val name: String) {
        constructor (name: String, age:Int) : this(name) {
            // 初始化...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    abstract抽象类
    如果一个类要被继承,可以使用 open 关键字进行修饰。

    open class Base {
        open fun f() {}
    }
    
    abstract class Derived : Base() {
        override abstract fun f()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    内部类使用 inner 关键字来表示。
    内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。

    class Outer {
        private val bar: Int = 1
        var v = "成员属性"
        /**嵌套内部类**/
        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) //   1
        val demo2 = Outer().Inner().innerTest()   
        println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    interface 与 匿名内部类

    class Test {
        var v = "成员属性"
    
        fun setInterFace(test: TestInterFace) {
            test.test()
        }
    }
    
    /**
     * 定义接口
     */
    interface TestInterFace {
        fun test()
    }
    
    fun main(args: Array<String>) {
        var test = Test()
    
        /**
         * 采用对象表达式来创建接口对象,即匿名内部类的实例。
         */
        test.setInterFace(object : TestInterFace {
            override fun test() {
                println("对象表达式创建匿名内部类的实例")
            }
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    类的修饰符

    abstract    // 抽象类  
    final       // 类不可继承,默认属性
    enum        // 枚举类
    open        // 类可继承,类默认是final的
    annotation  // 注解类
    
    private    // 仅在同一个文件中可见
    protected  // 同一个文件中或子类可见
    public     // 所有调用的地方都可见
    internal   // 同一个模块中可见
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    属性重写使用 override 关键字

    open class Foo {
        open val x: Int get { …… }
    }
    
    class Bar1 : Foo() {
        override val x: Int = ……
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    扩展函数

    class User(var name:String)
    
    /**扩展函数**/
    fun User.Print(){
        print("用户名 $name")
    }
    
    fun main(arg:Array<String>){
        var user = User("Runoob")
        user.Print()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    伴生对象的扩展

    class MyClass {
        companion object { }  // 将被称为 "Companion"
    }
    
    fun MyClass.Companion.foo() {
        println("伴随对象的扩展函数")
    }
    
    val MyClass.Companion.no: Int
        get() = 10
    
    fun main(args: Array<String>) {
        println("no:${MyClass.no}")
        MyClass.foo()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    数据类,声明一个密封类,使用 data 修饰类

    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)
        println(jack)
        println(olderJack)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    密封类,声明一个密封类,使用 sealed 修饰类

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    泛型

    class Box<T>(t: T) {
        var value = t
    }
    val box: Box<Int> = Box<Int>(1)
    // 或者
    val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box
    
    
    fun <T> boxIn(value: T) = Box(value)
    
    // 以下都是合法语句
    val box4 = boxIn<Int>(1)
    val box5 = boxIn(1)     // 编译器会进行类型推断
    
    // Comparable上约束
    fun <T : Comparable<T>> sort(list: List<T>) {
        // ……
    }
    
    
    
    // 使用 out 使得一个类型参数协变
    // 定义一个支持协变的类
    class Runoob<out A>(val a: A) {
        fun foo(): A {
            return a
        }
    }
    
    fun main(args: Array<String>) {
        var strCo: Runoob<String> = Runoob("a")
        var anyCo: Runoob<Any> = Runoob<Any>("b")
        anyCo = strCo
        println(anyCo.foo())   // 输出 a
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    对象表达式

    // 通过对象表达式实现一个匿名内部类的对象用于方法的参数中
    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            // ...
        }
        override fun mouseEntered(e: MouseEvent) {
            // ...
        }
    })
    
    // 对象可以继承于某个基类,或者实现其他接口
    open class A(x: Int) {
        public open val y: Int = x
    }
    
    interface B {……}
    
    val ab: A = object : A(1), B {
        override val y = 15
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    SpringCloud Alibaba微服务第6章之Gateway
    基于Simulink宽带单基地雷达系统仿真(附源码)
    关键路径法的“关键”是什么?是项目经理的进度把控能力!
    订单。。。
    2023年中国玉米淀粉糖市场现状及行业需求前景分析[图]
    java优雅去除 NullPointerException 空指针异常
    Postgresql 模块插件之pg_stat_statements
    PS 证件照换底色
    Python 机器学习入门之逻辑回归
    【Java】方法隐藏 vs 方法重写
  • 原文地址:https://blog.csdn.net/a__int__/article/details/127864800