美文网首页kotlin
Kotlin 学习笔记(四)类、继承、重构、构造函数、接口

Kotlin 学习笔记(四)类、继承、重构、构造函数、接口

作者: _明川 | 来源:发表于2019-05-22 15:13 被阅读0次
    SeaCliffBridge_ZH-CN5362667487_1920x1080.jpg

    前言
    本文章只是用于记录学习,所以部分地方如果有错误或者理解不对的地方,麻烦请指正。本篇为 csdn 原文章 转移修改版 原文章

    Kotlin 学习笔记(三)

    简述:

    1. kotlin 中接口的简单使用
    2. kotlin 中 类和属性的继承
    3. kotlin 中类的重载函数
    4. kotlin 中修饰符的介绍
    5. kotlin 中嵌套类 内部类的讲解
    6. kotlin 的主构造函数和次构造函数

    1.接口

    相比于 java 的接口,kotlin 还是有点不同的

    1.Kotlin 的接口声明 默认都是 final 和 public 的
    2.Kotlin 中的接口 和 java 1.8 接口相似,可以包含 抽象方法的定义 和 非抽象方法的实现

    // 接口
    interface Clicker{
        fun click()
    }
    
    // 实现类
    class MeButton : Clicker{
        override fun click() {
            println("not implemented")
        }
    }
    
    // 调用
    fun main(args: Array<String>) {
        var button:MeButton = MeButton()
        button.click()
    }
    

       上述代码,我们看到 kotlin 中 使用 “:” 代替了 java 中的 extends 和 implements , 和 java 相同的,kotlin 也是单继承,但是可以实现多个接口。和java 中的 @override 相同,override 用来注释 继承父类的方法,或者 接口的方法或属性,不同的是 kotlin 中的 override 是强制添加上的,这样可以避免先写实现方法 在添加抽象方法 造成的重写。
    kotlin 接口中可以有默认实现的方法,但是java 中则需要在方法中表明 default 关键字,而kotlin中是不用添加 关键字的。

    interface Clicker{
        fun click()
        fun staticClick(){
            println("默认实现")
        }
    }
    

       如果你 实现了这个接口,你也可以继承该方法,对他进行修改,当然你也可以不实现该方法。

    1.如果 你分别继承两个 接口,两个接口有相同的默认实现函数,如果不显式的指明调用哪一个,运行的时候会报错。
    2.解决办法就是 实现两个接口中相同名称的函数,在函数中指明引用,
    2.1 super< AInterface >.click(); super< BInterface >.click(); 而在java中的表达方式则是 AInterface .super.click(); 表现方式不太一样

    2. 继承

     2.1 继承函数

      java 中的父类默认都是 可以继承的,所以我们在写 BaseActivity 或者 BaseFragment 的时候都要慎重的设计,因为一不小心 就会让子类实现很多没有的类。所以 kotlin中 的方法默认都是 final ,如果需要子类继承就要特地标记 open 修饰符。

    class MeButton : Clicker{
        override fun click() {  // 实现 Clicker 方法 默认 为open 可继承
            println("not implemented")
        }
    
        fun dieable(){}   // 默认为 final
    
        open fun openClass(){}  // 明确表明 为open 可继承
    }
    

       如果是实现 基类的方法 或者 接口的方法,默认是open 的,如果希望改变,可以自己添加修饰符 final 。

    Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类

     2.2 继承属性

       继承属性和继承函数差不多,在父类中声明然后在子类中重新声明的属性必须以 override 开头,并且它们必须具有兼容的类型。每个声明的属性可以由具有初始化器的属性或者具有 getter 方法的属性覆盖。
       注意: var 属性可以继承自一个 val 属性 ,反之则不可以。(var 属性不能 让val 继承 )

    interface Foo {
        val count: Int
    }
    
    class Bar1(override val count: Int) : Foo
    
    class Bar2 : Foo {
        override var count: Int = 0
    }
    

       上述代码,我们在主构造函数中也可以使用 override 。

     2.3 abstract

    我们通过一段代码 来了解一下 abstract

    // 抽象类,不能创建实例
    abstract class abClas{
        // 抽象方法 默认就是open(此处省略) 不能实例,必须继承实现
        abstract fun  ab1()
        //抽象类中的 方法 不是默认open的,所以需要标明
        open fun ab2(){}
        
        fun ab3(){}
    }
    

    其他地方和 java 的都比较相似,这里就不多赘述

    2.4 重载函数

    由于在Java中是没有默认值参数的概念,当我们需要从Java中调用Kotlin中的默认值重载函数的时候,必须显示的指定所有参数值。但是这个绝对不是我们想要,否则Kotlin就失去了重载的意义了不能和Java完全互操作。所以在Kotlin给出了另一个方案就是使用@JvmOverloads注解这样就会自动生成多个重载方法供Java调用。

    @JvmOverloads
    fun <T> joinString(
            collection: Collection<T> = listOf(),
            separator: String = ",",
            prefix: String = "",
            postfix: String = ""
    ): String {
        return collection.joinToString(separator, prefix, postfix)
    }
    
    //调用的地方
    fun main(args: Array<String>) {
        //函数使用命名参数可以提高代码可读性
        println(joinString(collection = listOf(1, 2, 3, 4), separator = "%", prefix = "<", postfix = ">"))
        println(joinString(collection = listOf(1, 2, 3, 4), separator = "%", prefix = "<", postfix = ">"))
        println(joinString(collection = listOf(1, 2, 3, 4), prefix = "<", postfix = ">"))
        println(joinString(collection = listOf(1, 2, 3, 4), separator = "!", prefix = "<"))
        println(joinString(collection = listOf(1, 2, 3, 4), separator = "!", postfix = ">"))
        println(joinString(collection = listOf(1, 2, 3, 4), separator = "!"))
        println(joinString(collection = listOf(1, 2, 3, 4), prefix = "<"))
        println(joinString(collection = listOf(1, 2, 3, 4), postfix = ">"))
        println(joinString(collection = listOf(1, 2, 3, 4)))
    }
    
    

    3. 修饰符

      和 java 的大多数修饰符是一样的,但是java 默认为 private ,但是kotlin 中默认为 public ,并且 kotlin中没有 包可见,新添加的修饰符为 :internal ,表示只在模块内部可用。

    这里写图片描述

    1.在kotlin 中 public 是不可以访问 低可见性 internal 的。
    2.另外还要注意的是 protected ,在java 中他的访问范围是 包中,但是在kotlin 中则是 局限到 类 或者子类中,

    1. 类的扩展函数 是访问不到 private 和 protected 的。

    4. 嵌套类 内部类

      和java 一样,kotlin 也是可以在类中 包 类,但是 内部类是不可以访问 外部类的属性的 ,除非你做 了特殊的 安排。

    class MeButton : Clicker {
        private var a: Int = 1
        override fun click() {
            println("not implemented")
        }
    
        fun dieable() {}
    
        open fun openClass() {}
        // inner 关键字是重点
        inner class CButton {
            var b: Int = a
        }
    }
    

      从上述代码中看到,我这里在 类 MeButton 中新添加了一个 类 CButton ,如果在没有添加 inner 的情况下,称之为 嵌套类,CButton 中是无法获取到外部类的引用的。
      如果添加上 inner 后,则算是内部类,可以获取到外部类的引用。

    5. 类

      类 不管是 在 java 和 kotlin 中都是比较重要的一部分,前边的几张我们也都写了很多 class 的代码 ,这里我们详细的讲解下。

    // Kotlin 中使用关键字 class 声明类
    class Invoice { ... }
    
    class Empty
    

       类声明由类名、类头 以及由花括号包围的类体构成。类头与类体都是可选的; 如果一个类没有类体,可以省略花括号。

     5.1 主构造函数

      Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名后

    class Person constructor(firstName: String) {  }
    
    class Person (firstName: String) {  }
    

     上述代码 就是典型的 构造函数,我们可以使用 constructor 关键字来形容,当然如果该类没有其他修饰符 可以省略 constructor 不写。

     5.2 初始化 init

    初始化的代码可以放到以 init 关键字作为前缀的初始化块中。

    初始化代码块

    class InitOrderDemo(name: String) {
        
        val secondProperty = "Second property: ${name.length}".also(::println)
        val customerKey = name.toUpperCase()
        val firstProperty = "First property: $name".also(::println)
        init {
            println("First initializer block that prints ${name}")
        }
    
        
        init {
            println("Second initializer block that prints ${name.length}")
        }
    }
    
    // 运行代码
    fun main(args: Array<String>) {
        InitOrderDemo("hello")
    }
    

    运行结果

    Second property: 5
    First property: hello
    First initializer block that prints hello
    Second initializer block that prints 5
    

      上段代码我们初步了解了 init 的使用方法, 主构造的参数可以在初始化块中使用 或者是 属性中(val customerKey = name.toUpperCase())。
    如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面:

    public class Customer @Inject constructor(name: String) { }
    

     5.3 次构造函数

    类也可以声明前缀有 constructor的次构造函数:

    class Person {
        // 次 构造函数
        constructor(parent: Person) {
            parent.children.add(this)
        }
    }
    

      如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可:

      初始化块 init 中的代码实际上会成为主构造函数的一部分。委托给主构造函数会作为次构造函数的第一条语句,因此所有初始化块中的代码都会在次构造函数体之前执行。即使该类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块

      如果一个 非 抽象类 没有声明 任何 构造函数,那么 程序会默认生成一个没有参数 可见性为 public 的主构造函数,如果你不希望你的类有一个公有构造函数,你需要声明一个带有非默认可见性的空的主构造函数。

    Kotlin 学习笔记(五)

    相关文章

      网友评论

        本文标题:Kotlin 学习笔记(四)类、继承、重构、构造函数、接口

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