• 类的基本概念
      • 用class关键字标识,加open修饰符表示可继承,实例化无需new val p = Person()
      • 可见修饰符:默认是public对所有类可见,protected关键字表示对当前类以及子类可见,private表示只对当前类可见,最后Kotlin新增了一个internal修饰符表示只对同一个模块中的类可见
      • 类主要包含:构造函数和初始化块,函数,属性,嵌套类和内部类,对象声明
    • 构造函数

      1. Kotlin中的构造函数分为两种:主构造函数和次构造函数,每个类都会有一个默认的不带参数的主构造函数,当然也可以显示的指明参数
      • 主构造函数:

    可以用constructor关键字标识,class Person constructor(name: String) {}, 如果主构造函数没有注释或者可见性修饰符可以省略这个关键字 class Person (name: String) {}。主构造函数没有函数体,需要一些初始化的工作可以在init {} 代码块中进行。

    • 次构造函数:

    一个类可以有多个次构造函数,但是必须要直接或者间接调用主构造函数,如下代码所示

    class Student (name: String, age: Int, gender: String, val grade):Person(name, age, gender) {
       constructor(name: String, age: Int, gender: String): this(name,age,gender,3){}
       constructor():this("Bob",20,"male")
    }
    
    //类没有显示定义主构造函数只有次构造函数时的写法
    
    class Student:Person {
       constructor(name:String, age:Int) : super(name, age) {}
    }
    
    • 继承及重写

      • 任何Kotlin的类都是有一个公共的父类Any,然后Any有三个方法equals(), hashCode(), toString(), 一个类默认是final不可继承的,如果想要它可继承就要加open关键字。同时如果父类有主构造函数,那么子类必须对其进行实现。如果父类没有主构造函数,那么就要在每个次构造函数中用super关键字对基类的进行实现如下代码所示:

        class MyView : View {
        constructor(ctx: Context) : super(ctx)
        
        constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
        }
        
      • 可以对方法进行重写如下代码所示,但是被重写的方法要被open修饰,且所在的类不能是final类型的 ```kotlin open class Shape { open fun draw() { // } fun fill() { // } }

    class Circle() : Shape() { override fun draw() { // } }

    //一个方法如果是被override修饰过了就默认为它是可被重写的,如果不想这样 //可以在前面加上final修饰符 open class Rectangle() : Shape() { final override fun draw() {//} }

    
       - 可以对属性进行重写,如下所示
    ```kotlin
    open class Shape {
      open val count: Int = 0
    }
    
    class Rectangle : Shape() {
      override val count = 45
    }
    
              也可以把val值重写为var但是要额外实现set方法,如下
    
    interface Shape {
        val vertexCount: Int
    }
    
    class Rectangle(override val vertexCount: Int = 4) : Shape // Always has 4 vertices
    
    class Polygon : Shape {
        override var vertexCount: Int = 0  // Can be set to any number later
    }
    
    • 派生类初始化顺序: 父类的构造函数执行后子类声明的属性才初始化,所以要注意尽量不要在基类中使用open members ```kotlin open class Base(val name: String) {

      init { println(“Initializing a base class”) }

      open val size: Int = name.length.also { println(“Initializing size in the base class: $it”) } }

    class Derived( name: String, val lastName: String, ) : Base(name.replaceFirstChar { it.uppercase() }.also { println(“Argument for the base class: $it”) }) {

    init { println("Initializing a derived class") }
    
    override val size: Int =
        (super.size + lastName.length).also { println("Initializing size in the derived class: $it") }
    

    }

    fun main() { println(“Constructing the derived class(\”hello\”, \”world\”)”) Derived(“hello”, “world”) }

    
    - **属性**
       - 一个完整的属性声明格式如下,
    ```kotlin
    var <propertyName>[: <PropertyType>] [= <property_initializer>]
        [<getter>]
        [<setter>]
    
    //val 没有set方法,完整格式如下
    class Rectangle(val width: Int, val height: Int) {
      val square: Int 
        get() = this.width * this.height
    }
    
    //var
    var stringRepresentation: String
      get() = this.toString()
      set(value) {
        setDataFromString(value)
      }
    //调用
    open class Person {
        var age: Int = 10
            //getter缺省为默认
            //setter设置参数前打印参数
            set(value) {
                println("setter $value")
                //field关键字指向属性本身
                field = value
            }
    }
    
    @JvmStatic
    fun main(args: Array<String>) {
        val p = Person()
        println(p.age)
        p.age = 30
        println(p.age)
    }
    
    • 幕后字段,field 标识符只能用在属性的访问器内。

      var counter = 0 // the initializer assigns the backing field directly
      set(value) {
        if (value >= 0)
            field = value
            // counter = value // ERROR StackOverflow: Using actual name 'counter' would make setter recursive
      }
      
    • 延迟初始化, 加上lateinit关键字, 用isInitialized来判断是否已经初始化了

      • 接口
    • Kotlin的接口和JAVA类似,一个类可以实现多个接口,接口中可以定义属性,但是必须是抽象的或者提供了访问器实现。接口中的属性没有backing field, 所以接口中声明的访问器不能引用它们 ```kotlin interface MyInterface { val prop: Int // 抽象的

      val propertyWithImplementation: String get() = “foo”

      fun foo() { print(prop) } }

    class Child : MyInterface { override val prop: Int = 29 }

    
       - 接口是可以继承的,所以它既可以实现父接口也可以定义新的属性
    ```kotlin
    interface Named {
        val name: String
    }
    interface Person : Named {
        val firstName: String
        val lastName: String
        override val name: String get() = "$firstName $lastName"
    }
    data class Employee(
        // implementing 'name' is not required
        override val firstName: String,
        override val lastName: String,
        val position: Position
    ) : Person
    
    • 接口重写冲突:

      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 <T> MutableList<T>.swap(index1: Int, index2: Int) {
        val tmp = this[index1] // 'this' corresponds to the list
        this[index1] = this[index2]
        this[index2] = tmp
        }
        
      • 拓展是静态的,如下代码会输出Shape。如果和成员函数有冲突则成员函数的优先级更高 ```kotlin open class Shape class Rectangle: Shape()

    fun Shape.getName() = “Shape” fun Rectangle.getName() = “Rectangle”

    fun printClassName(s: Shape) { println(s.getName()) }

    printClassName(Rectangle())

    
       - 拓展属性由于没有实际的将成员插入类中,幕后字段是无效的,所以不能有初始化容器只能显示定义setters和 getters,如下代码
    ```kotlin
    val <T> List<T>.lastIndex:Int
       get() = size - 1
    //下面代码会报错
    val House.number = 1
    
    • 对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。引用分发接收者的成员要用this。
      class Connection {
      fun Host.getConnectionString() {
        toString()         // 调用 Host.toString()
        this@Connection.toString()  // 调用 Connection.toString()
      }
      }
      
    • 泛型

      • Kotlin中也有泛型的概念,但是如果可以推断的出来就可以省略类型参数

        class Box<T>(t:T) {
        var value = t
        }
        //带类型参数的
        val box:Box<Int> = Box<Int>(1)
        //不带类型参数
        val box = Box(1)
        
      • Kotlin中的泛型可以加In和Out修饰符,当一个类 C 的类型参数 T 被声明为 out 时它只能被消费,而In只能用于生产,这样可以防止一些类型安全的问题。下面是out和in的示例: ```kotlin //泛型接口 Source中不存在任何以 T 作为参数的方法,只是返回 T 类型值 interface Source { T nextT(); } //在 Source 类型的变量中存储 Source 实例的引用是极为安全的 void demo(Source strs) { Source objects = strs; // !!!在 Java 中不允许 // …… } interface Source { fun nextT(): T }

        fun demo(strs: Source) { val objects: Source = strs // 这个没问题,因为 T 是一个 out-参数 // …… }

        
           -   //tofinis
        - ** 密封类**
           - 密封类的子类在编译期间就可以知道了,编译过后不可以加新的子类。密封类的构造函数有两种可见性修饰符,分别为protected和private,如下所示
        ```kotlin
        sealed class IOError {
           constructor()
           private constructor(description: String): this() {}
        }
        
        • 嵌套类和内部类
          • 类和接口都可以嵌套在类或接口中,如下。然后一个类加inner表示是内部类可访问外部类的相关属性 ```kotlin interface OuterInterface { class InnerClass interface InnerInterface }

        class OuterClass { class InnerClass interface InnerInterface }

        
        - ** 内联类**
           - 为了降低容器的性能开销。Kotlin中定义了内联类,用value标识(最新的Kotlin中已不再使用inline),内联类中可以有属性,函数和初始化块但不能有返回值,内联类也可以实现接口但不能参与类的继承
        ```kotlin
        @JvmInline
        value class Name(val s: String) {
            init {
                require(s.length > 0) { }
            }
        
            val length: Int
                get() = s.length
        
            fun greet() {
                println("Hello, $s")
            }
        }
        
        fun main() {
            val name = Name("Kotlin")
            name.greet() // method `greet` is called as a static method
            println(name.length) // property getter is called as a static method
        }
        
        • 内联类在运行时可以表示为包装器或者基础类型,编译更倾向于包装器而当内联类被用作另一种类型时就会被装箱,如下 ```kotlin interface I

        inline class Foo(val i: Int) : I

        fun asInline(f: Foo) {} fun asGeneric(x: T) {} fun asInterface(i: I) {} fun asNullable(i: Foo?) {}

        fun id(x: T): T = x

        fun main() { val f = Foo(42)

        asInline(f)    // 拆箱操作: 用作 Foo 本身
        asGeneric(f)   // 装箱操作: 用作泛型类型 T
        asInterface(f) // 装箱操作: 用作类型 I
        asNullable(f)  // 装箱操作: 用作不同于 Foo 的可空类型 Foo?
        
        // 在下面这里例子中,'f' 首先会被装箱(当它作为参数传递给 'id' 函数时)然后又被拆箱(当它从'id'函数中被返回时)
        // 最后, 'c' 中就包含了被拆箱后的内部表达(也就是 '42'), 和 'f' 一样
        val c = id(f)  
        

        } ```

        • 委托
          • //todo