美文网首页
Kotlin笔记

Kotlin笔记

作者: 雇个城管打天下 | 来源:发表于2018-02-11 21:55 被阅读11次

    为什么是Kotlin?

    下面是官网给的解释


    开发IDE : IDEA / Android Studio
    参考:Kotlin 语言中文站
    总之Kotlin是目前最有可能取代Java的一门语言,你说你要不要学?

    Kotlin基础语法

    函数定义

    函数定义使用关键字fun,参数格式为:参数:类型

    fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int
        return a + b
    }
    

    表达式作为函数体时,返回类型自动判断

    fun sum(a: Int, b: Int) = a + b
    

    注意

    // public 方法则必须明确写出返回类型
    public fun sum(a: Int, b: Int): Int = a + b   
    

    无返回值的函数(类似Java中的void):

    fun printSum(a: Int, b: Int): Unit { 
        print(a + b)
    }
    
    
    // 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
    public fun printSum(a: Int, b: Int) { 
        print(a + b)
    }
    

    常量定义和变量定义

    1. 可变变量定义:var关键字
    var <标识符> : <类型> = <初始化值>
    
    1. 不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)
    val <标识符> : <类型> = <初始化值>
    

    常量与变量都可以没有初始化值,但是在引用前必须初始化
    编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。

    示例:

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

    注释

    和java类似,支持单行注释和多行注释,不同的是,Kotlin中的块注释允许嵌套

    // 这是一个单行注释
    
    /* 这是一个多行的
       块注释。 */
    

    字符串模板

    $ 表示一个变量名或者变量值
    $varName 表示变量值
    ${varName.fun()} 表示变量的方法返回值

    var a = 1
    // 模板中的简单名称:
    val s1 = "a is $a" 
    
    a = 2
    // 模板中的任意表达式:
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    

    NULL 检查机制

    Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理

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

    区间

    区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
    区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:

        for (i in 1..4) print("$i ")    //输出1 2 3 4
        println()
        for (i in 4..1) print("$i ")    //什么也不输出4
        println()
        for (i in 4 downTo 1) print("$i ")    //倒序应该用downTo
        println()
    
        for (i in 1..10) {
            // 等同于 1 <= i && i <= 10
            //[1,10]
            print("$i ")
        }
        println()
    
        // 使用 until 函数排除结束元素
        for (i in 1 until 10) {
            // 等同于 1 <= i && i < 10
            //[1,10)
            print("$i ")
        }
        println()
    
        for (i in 1..4 step 2) print("$i ")         //输出1 3
        println()
    
        for (i in 4 downTo 1 step 2) print("$i ")   //输出4 2
        println()
    

    Kotlin基本数据类型

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

    比较两个数字

    在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

    fun main(args: Array<String>) {
        val a: Int = 10000
        println(a === a) // true,值相等,对象地址相等
    
        //经过了装箱,创建了两个不同的对象
        val boxedA: Int? = a
        val anotherBoxedA: Int? = a
    
        //虽然经过了装箱,但是值是相等的,都是10000
        println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
        println(boxedA == anotherBoxedA) // true,值相等
    }
    

    类型转换

    每种数据类型都有下面的这些方法,可以转化为其它的类型:

    toByte(): Byte
    toShort(): Short
    toInt(): Int
    toLong(): Long
    toFloat(): Float
    toDouble(): Double
    toChar(): Char
    

    例如:

    val b: Byte = 1 // OK, 字面值是静态检测的
    val i: Int = b.toInt() // OK
    

    Kotlin条件控制

    Kotlin中表达条件控制的有两种表达式

    1. if表达式
    2. when表达式

    if表达式的用法

    其实个人感觉对于if的用法,java和kotlin并没有什么区别,有点不太一样的就是可以把if表达式的结果赋值给一个变量,如下:

    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
    

    所以也就可以有下面这样的写法了

    val c = if (condition) a else b
    

    when表达式的用法

    when表达式就和java里面的switch类似,最简单的形式如下:

    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块
            print("x 不是 1 ,也不是 2")
        }
    }
    

    在when语句中,else同switch语句中的default,如果其他分支都不满足条件将会进入else分支,当然,如果很多分支需要相同的处理方式,可以把多个分支条件放在一起,用逗号分隔,例如:

    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    

    我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:

    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")
    }
    

    另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法和属性而无需 任何额外的检测。

    fun hasPrefix(x: Any) = when(x) {
        is String -> x.startsWith("prefix")
        else -> false
    }
    

    实例:

    fun main(args: Array<String>) {
        val x = 0
        if (x > 0) {
            println("x大于0")
        } else if (x == 0) {
            println("x等于0")
        } else {
            println("小于0")
        }
    
        val a = 1
        val b = 2
        val c = if (a >= b) a else b
        println("c的值为 $c")
    
        when (x) {
            0, 1 -> println("x==0 or x==1")
            else -> println("otherwise")
    
        }
    
        when (x) {
            1 -> println("x==1")
            2 -> println("x==2")
            else -> {
                println("x 不是1,也不是2")
            }
        }
    
        when (x) {
            in 0..10 -> println("x在该区间范围内")
            else -> println("x不在该区间范围内")
        }
    }
    

    Kotlin循环控制

    和Java一样,kotlin循环也有三种形式,for循环,while循环和do....while循环。但是用法却有些不同。

    for循环

    基本用法如下:

    for (item: Int in ints) {
        // ……
    }
    

    实例如下:

    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]}")
        }
    }
    

    执行结果如下:

    apple
    banana
    kiwi
    item at 0 is apple
    item at 1 is banana
    item at 2 is kiwi
    

    注意!!

    在kotlin中使用的for循环语句和java里面的for循环语句相类似,但是不可以使用
    for(int i=0;i<n;i++)这样的语句

    while循环和do...while循环

    while循环是最基本的循环方式,基本结构为:

    while( 布尔表达式 ) {
     //循环内容
    }
    

    do...while 循环的基本结构为:

    do {
           //代码语句
    }while(布尔表达式);
    

    理解起来和Java里面的while循环和do...while循环一致,参考实例如下:

    fun main(args: Array<String>) {
        println("----while 使用-----")
        var x = 5
        while (x > 0) {
            println( x--)
        }
        println("----do...while 使用-----")
        var y = 5
        do {
            println(y--)
        } while(y>0)
    }
    

    输出结果:

    ----while 使用-----
    5
    4
    3
    2
    1
    ----do...while 使用-----
    5
    4
    3
    2
    1
    

    循环返回和跳转

    Kotlin 有三种结构化跳转的表达式:

    1. return
    2. break
    3. continue
      理解起来和Java中的一样,基本用法也一致,但是在kotlin中break和continue有新的用法

    Break 和 Continue 标签

    在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。

    loop@ for (i in 1..100) {
        for (j in 1..100) {
            if (……) break@loop
        }
    }
    

    标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。

    通过指定标签就可以明确的指定出在什么时候退出哪一个循环

    Kotlin类和对象

    Kotlin类中可以包含以下几个东西:

    1. 构造函数和初始化代码块
    2. 成员函数
    3. 属性
    4. 内部类
    5. 对象声明

    Kotlin中使用关键字class声明类,后面紧跟类名,在类中可以定义成员函数,格式如下:

    class Temp{
        //类名为Temp
        //大括号里面是类体构成
        fun f(){
            println("这是成员函数")
        }
    }
    

    类的属性

    类的属性用关键字var声明为可变的,否则就用val声明为不可变

    class Temp{
        var name: String = ……
        var url: String = ……
        var city: String = ……
    }
    

    也可以像使用普通函数那样使用构造函数创建类实例:

    val temp= Temp() // Kotlin 中没有 new 关键字
    

    想要使用一个属性,只需要用名称引用即可

    temp.name
    temp.url
    

    这里需要注意的是,kotlin中并没有new关键字,实例化一个对象的时候不需要像java一样通过new关键字实例化。

    getter和setter

    getter和setter属性都是可选的,用法和c#中的get和set方法类似
    如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型

    注意!!! val不允许设置setter函数,因为该函数是只读的。

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

    实例

    下面实例定义了一个Person类,包含两个可变变量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法。

    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}")
    
    }
    

    输出结果为:

    lastName:WANG
    no:9
    no:-1
    

    Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器

    主构造器和次构造器

    Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:

    class Person constructor(firstName: String) {}
    

    如果主构造器没有任何注解,也没有任何可见度修饰符,那么可以省略constructor关键字

    class Person(firstName: String) {}
    

    主构造器

    主构造器中不能包含任何代码,初始化代码可以当在初始化代码段中,用init关键字作为前缀

    class Person constructor(firstName: String) {
        init {
            System.out.print("FirstName is $firstName")
        }
    }
    

    实例:

    class Runoob  constructor(name: String) {  // 类名为 Runoob
        // 大括号内是类体构成
        var url: String = "http://www.runoob.com"
        var country: String = "CN"
        var siteName = name
    
        init {
            println("初始化网站名: ${name}")
        }
    
        fun printTest() {
            println("我是类的函数")
        }
    }
    
    fun main(args: Array<String>) {
        val runoob =  Runoob("菜鸟教程")
        println(runoob.siteName)
        println(runoob.url)
        println(runoob.country)
        runoob.printTest()
    }
    

    次构造函数

    类也可以有二级构造函数,并且可以有多个,需要加前缀constructor

    class Person { 
        constructor(parent: Person) {
            parent.children.add(this) 
        }
    }
    

    如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

    class Person(val name: String) {
        constructor (name: String, age:Int) : this(name) {
            // 初始化...
        }
    }
    

    实例:

    class Runoob  constructor(name: String) {  // 类名为 Runoob
        // 大括号内是类体构成
        var url: String = "http://www.runoob.com"
        var country: String = "CN"
        var siteName = name
    
        init {
            println("初始化网站名: ${name}")
        }
        // 次构造函数
        constructor (name: String, alexa: Int) : this(name) {
            println("Alexa 排名 $alexa")
        }
    
        fun printTest() {
            println("我是类的函数")
        }
    }
    
    fun main(args: Array<String>) {
        val runoob =  Runoob("菜鸟教程", 10000)
        println(runoob.siteName)
        println(runoob.url)
        println(runoob.country)
        runoob.printTest()
    }
    

    Kotlin继承

    kotlin中所有的类都继承Any类,如果一个类要被继承,需要使用open关键字进行修饰

    open class Base(p: Int)           // 定义基类
    
    class Derived(p: Int) : Base(p)
    

    构造函数

    子类有主构造函数,则基类必须在主构造函数中立即初始化

    open class Person(var name : String, var age : Int){// 基类
    
    }
    
    class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {
    
    }
    
    // 测试
    fun main(args: Array<String>) {
        val s =  Student("Runoob", 18, "S12346", 89)
        println("学生名: ${s.name}")
        println("年龄: ${s.age}")
        println("学生号: ${s.no}")
        println("成绩: ${s.score}")
    }
    

    子类中没有主构造函数

    如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

    /**用户基类**/
    open class Person(name:String){
        /**次级构造函数**/
        constructor(name:String,age:Int):this(name){
            //初始化
            println("-------基类次级构造函数---------")
        }
    }
    
    /**子类继承 Person 类**/
    class Student:Person{
    
        /**次级构造函数**/
        constructor(name:String,age:Int,no:String,score:Int):super(name,age){
            println("-------继承类次级构造函数---------")
            println("学生名: ${name}")
            println("年龄: ${age}")
            println("学生号: ${no}")
            println("成绩: ${score}")
        }
    }
    
    fun main(args: Array<String>) {
        var s =  Student("Runoob", 18, "S12345", 89)
    }
    

    重写

    如果允许子类重写,那么就要手动添加open修饰,重写的方法用override关键词修饰:

    /**用户基类**/
    open class Person{
        open fun study(){       // 允许子类重写
            println("我毕业了")
        }
    }
    
    /**子类继承 Person 类**/
    class Student : Person() {
    
        override fun study(){    // 重写方法
            println("我在读大学")
        }
    }
    
    fun main(args: Array<String>) {
        val s =  Student()
        s.study();
    
    }
    

    如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

    open class A {
        open fun f () { print("A") }
        fun a() { print("a") }
    }
    
    interface B {
        fun f() { print("B") } //接口的成员变量默认是 open 的
        fun b() { print("b") }
    }
    
    class C() : A() , B{
        override fun f() {
            super<A>.f()//调用 A.f()
            super<B>.f()//调用 B.f()
        }
    }
    
    fun main(args: Array<String>) {
        val c =  C()
        c.f();
    
    }
    

    Kotlin接口

    在kotlin中接口和java8中的用法类似,都是用interface关键字定义接口,允许有默认方法的实现。

    接口中的方法

    实例:

    interface MyInterface {
        fun bar()
        fun foo() {
            // 可选的方法体
            println("foo")
        }
    }
    class Child : MyInterface {
        override fun bar() {
            // 方法体
            println("bar")
        }
    }
    fun main(args: Array<String>) {
        val c =  Child()
        c.foo();
        c.bar();
    }
    

    接口中的属性

    接口中的属性只能是抽象的,不允许初始化值,接口不会爆粗 属性值,实现接口的时候,必须重写属性。
    实例:

    interface MyInterface {
        var name:String //name 属性, 抽象的
        fun bar()
        fun foo() {
            // 可选的方法体
            println("foo")
        }
    }
    class Child : MyInterface {
        override var name: String = "runoob" //重载属性
        override fun bar() {
            // 方法体
            println("bar")
        }
    }
    fun main(args: Array<String>) {
        val c =  Child()
        c.foo();
        c.bar();
        println(c.name)
     
    }
    

    函数重写

    接口中的方法的重写和继承类中的方法重写类似,实例如下:

    interface A {
        fun foo() { print("A") }   // 已实现
        fun bar()                  // 未实现,没有方法体,是抽象的
    }
     
    interface B {
        fun foo() { print("B") }   // 已实现
        fun bar() { print("bar") } // 已实现
    }
     
    class C : A {
        override fun bar() { print("bar") }   // 重写
    }
     
    class D : A, B {
        override fun foo() {
            super<A>.foo()
            super<B>.foo()
        }
     
        override fun bar() {
            super<B>.bar()
        }
    }
     
    fun main(args: Array<String>) {
        val d =  D()
        d.foo();
        d.bar();
    }
    

    相关文章

      网友评论

          本文标题:Kotlin笔记

          本文链接:https://www.haomeiwen.com/subject/wqmltftx.html