android巩固-kotlin第二篇

类和对象

/* -------------- 类和对象 -------------- */
/**
Kotlin 类可以包含:构造函数和初始化代码块、函数、属性、内部类、对象声明。
class Runoob {  // 类名为 Runoob
// 大括号内是类体构成
}

声明空类
class Empty

成员函数
class Runoob {
fun foo(){}
}

类的属性
class Runoob {
var name:String
var url:String
var city:String
}

实例的创建
val site = Runoob()
属性的引用
site.name="zzz"
site.url="action.call"

构造方法
class Person constructor(firstName:String){}
如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。
class Person(firstName:String){}

getter 和 setter

var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

getter 和 setter 都是可选

如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型,val不允许设置setter函数,因为它是只读的。

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

class Person {
    var lastName: String = "zhang"
        get() = field.toUpperCase()
        set

    /*Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器*/
    var no: Int = 100
        get() = field
        set(value) {
            if (value < 10) {
                field = value
            } else {
                field = -1
            }
        }

    var height: Float = 145.4f
        private set
}

fun t_obj_person() {
    val person = Person()
    person.lastName = "ratel"
    println("lastName = ${person.lastName}")
    person.no = 9
    println("no = ${person.no}")
    person.no = 21
    println("no = ${person.no}")
}


public class MyTest {
    // 非空属性必须在定义的时候初始化,kotlin提供了一种可以延迟初始化的方案,使用 lateinit 关键字描述属性
    lateinit var subject: TestSubject

    @SetUp
    fun setup() {
        subject = TestSubject()
    }

    @Test
    fun test() {
        subject.method()
    }
}

annotation class SetUp
annotation class Test

class TestSubject {
    fun method() {
    }

}

/**主构造器
 *  主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码使用init关键字
 */
class BookBean constructor(name: String) {
    init {
        println("book name $name")
    }
}

/**
 * 注意:主构造器的参数可以在初始化代码段中使用,也可以在类主体n定义的属性初始化代码中使用。 一种简洁语法,可以通过主构造器来定义属性并初始化属性值(可以是var或val):
 *  val 定义的常量是不可以修改的
 *  如果构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。
 */
class People(val firstName: String, val lastName: String) {
    init {
        println("firstName $firstName , lastName $lastName")
    }
}

fun t_consutrctor() {
    BookBean("三国")
    People("kagle", "ai")
}


class Runoob constructor(name: String) {
    var url = "http://www.runoob.com"
    var contry: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: $name")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun t_runoob() {
    val runoob = Runoob("菜鸟教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.contry)
    runoob.printTest()
}

/**
 * 次构造函数
类也可以有二级构造函数,需要加前缀 constructor:
 */
class NewPerson {
    private val children: Children = Children()

    constructor(parent: NewPerson) {
        parent.children.add(this)
    }
}

/**
 * 如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。
 * 在同一个类中代理另一个构造函数使用 this 关键字:
 */
class NewPerson2 constructor(val name: String) {
    var age: Int = 0

    init {
        println("NewPerson2 init name : $name")
    }


    constructor(name: String, _age: Int) : this(name) {
        age = _age
        // 初始化
        println("NewPerson2 次构造 : name : $name , age : $age")
    }
}

fun t_new_person2() {
    val newPerson2 = NewPerson2("zzg", 32)
    println("user name ${newPerson2.name} , age ${newPerson2.age}")
}

class Children {
    var pList = ArrayList<NewPerson>()

    fun add(person: NewPerson) {
        if (!pList.contains(person)) {
            pList.add(person)
        }
    }
}

/**
 *如果一个非抽象类没有声明构造函数(主构造函数或次构造函数),它会产生一个没有参数的构造函数。构造函数是 public 。如果你不想你的类有
 * 公共的构造函数,你就得声明一个空的主构造函数
 */
class DontCreateMe private constructor() {

}

/**
 * 注意:在 JVM 虚拟机中,如果主构造函数的所有参数都有默认值,编译器会生成一个附加的无参的构造函数,这个构造函数会直接使用默认值。这使得 Kotlin 可以更简单的使用像 Jackson 或者 JPA 这样使用无参构造函数来创建类实例的库。
class Customer(val customerName: String = "")
 */
/* -------------- 类和对象 -------------- */


/* -------------- 抽象类 -------------- */
/**
 * 抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。
注意:无需对抽象类或抽象成员标注open注解。
 */
open class BaseHandler {
    open fun f() {}
}

// 抽象类
abstract class BaseDefaultHanlder : BaseHandler() {
    // 抽象方法
    override abstract fun f()

}
/* -------------- 抽象类 -------------- */

/* -------------- 嵌套类(静态内部类) -------------- */
class Outer {
    private val bar: Int = 1

    class Nested {

        var ot: Outer = Outer()

        fun test() {
            // 嵌套类可以引用外部类私有变量,但要先创建外部类的实例,不能直接引用
            println(ot.bar)
        }

        fun foo() = 2
    }
}

// 调用格式:外部类.嵌套类.嵌套类方法/属性
fun t_nest_cls() {
    // 嵌套类,Outter后边没有括号
    val foo = Outer.Nested().foo()
    println("foo = $foo")
}
/* -------------- 嵌套类(静态内部类) -------------- */

/* -------------- 内部类 -------------- */
/**
 * 内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
 */
class Outer2 {
    private val bar: Int = 2
    var v = "成员属性"

    /*嵌套内部类*/
    inner class Inner2 {
        // 访问外部类成员
        fun foo() = bar

        fun innterTest() {
            // 获取外部类的成员变量
            // 相当于Outer.this
            /*
            为了消除歧义,要访问来自外部作用域的 this,我们使用this@label,
            其中 @label 是一个 代指 this 来源的标签。
            */
            var o = this@Outer2
            println("Outer2 内部类可以引用外部类的成员: v " + o.v)
        }
    }
}

fun t_inner_cls() {
    // 内部类,Outter后边有括号
    //
    val foo = Outer2().Inner2().foo()
    println("t_inner_cls foo = $foo")

    val d = Outer2().Inner2().innterTest()
    println("t_inner_cls d = $d")
}
/* -------------- 内部类 -------------- */

/* -------------- 匿名内部类 -------------- */
/*使用对象表达式来创建匿名内部类*/

class Test2 {
    var v = "成员属性"

    fun setInterFace(test: ITest) {
        println("Test2 setInterFace v = $v ")
        test.test()
    }
}

// 定义接口
interface ITest {
    fun test()
}

fun t_anonymous() {
    val test2 = Test2()
    /**
     * 采用对象表达式来创建接口对象,即匿名内部类的实例
     */
    test2.setInterFace(object : ITest {
        override fun test() {
            println("接口回调,对象表达式创建匿名内部类的实例")
        }
    })
}
/* -------------- 匿名内部类 -------------- */

/* -------------- 类的修饰符 -------------- */
/**
 * 类的修饰符包括 classModifier 和_accessModifier_:
 * classModifier: 类属性修饰符,标示类本身特性。

abstract    // 抽象类
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类

accessModifier: 访问权限修饰符

private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见
 */
private fun foo() {} // 在包类可见,包级函数

public var bar: Int = 5 // 该属性随处可见

internal val baz = 6 // 相同模块内可见

/* -------------- 类的修饰符 -------------- */

fun main(args: Array<String>) {
    t_obj_person()
    t_consutrctor()
    t_runoob()
    t_new_person2()
    t_nest_cls()
    t_inner_cls()
    t_anonymous()
}

继承

/* -------------- 继承 -------------- */
/**
kotlin中所有的类都继承Any,它是所有类的超父,对于没有超类型声明的类默认继承超类
class Exemaple // 从Any隐式继承
Any默认提供三个函数:equals,hashCode,toString

Any不是java.lang.Object
如果一个类要被继承,可以使用open关键字进行修饰
 */

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

class Dervied(p: Int) : Base(p)
/* -------------- 继承 -------------- */

/* -------------- 构造函数 -------------- */
/**
 *子类有主构造函数
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化
 */
open class New_EPerson(var name: String, var age: Int) { // 基类

}

class Student(name: String, age: Int, var no: String, var score: Int) : New_EPerson(name, age) {

}

fun t_ext_obj() {
    val student = Student("runnob", 18, "S0035", 89)
    println("姓名: ${student.name}")
    println("年龄: ${student.age}")
    println("学生号: ${student.no}")
    println("学分: ${student.score}")
}


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

open class Animal constructor(ctx: Context) {
    // 次构造
    constructor(ctx: Context, attrs: AttributeSet) : this(ctx)
}

class Cat : Animal {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

//实例

open class User(name: String) {
    // 次级构造函数
    constructor(name: String, age: Int) : this(name) {
        println("---------- 基类次级构造函数 ----------")
    }
}

class Worker : User {
    constructor(name: String, age: Int, no: String, score: Int) : super(name, age) {
        println("---------- 继承类次级构造函数 ----------")
        println("Worker 姓名: $name")
        println("Worker 年龄: $age")
        println("Worker 学生号: $no")
        println("Worker 学分: $score")
    }
}

fun t_ext_user() {
    Worker("test01", 23, "S1174", 135)
}


/**
 *重写
在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,
那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词
 */
// 用户基类
open class NewUser {
    open fun study() { // 允许子类重写
        println("我毕业了")
    }
}

/*子类继承NewUser类*/
class NewStudent : NewUser() {
    override fun study() { // 重写方法
        println("我在读大学")
    }
}

fun t_ode() {
    val student = NewStudent()
    student.study()
}

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

    fun a() {
        println("a")
    }
}

interface B {
    //  //接口的成员变量默认是 open 的
    fun f() {
        println("B")
    }

    fun b() {
        println("b")
    }
}

class C() : A(), B {
    override fun f() {
        println("C run f ... ")
        // 选择性的去调用父类的实现
        super<A>.f()
        super<B>.f()
    }
}

fun t_oc() {
    val c = C()
    c.f()
}

/**
 * 属性重写
属性重写使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写:
 */
open class Foo {
    open val x: Int
        get() = 10
}

class Bar1 : Foo() {
    override val x: Int
        get() = super.x
}

/**
 *
你可以用一个var属性重写一个val属性,但是反过来不行。因为val属性本身定义了getter方法,重写为var属性会在衍生类中额外声明一个setter方法
你可以在主构造函数中使用 override 关键字作为属性声明的一部分:
 */
interface IFoo {
    val count: Int
}

class Bar_1(override val count: Int) : IFoo

class Bar_2 : IFoo {
    override var count: Int = 0
}

/* -------------- 构造函数 -------------- */
fun main(args: Array<String>) {
    t_ext_obj()

    t_ext_user()

    t_ode()

    t_oc()
}

接口

/* -------------- 接口 -------------- */
//接口与java8类似,使用interface定义,允许方法有默认实现
interface IMe {
    fun bar()

    fun foo() {
        // 默认实现
        println("foo")
    }
}

/**
 * 实现接口
 *  一个类或者对象可以实现一个或多个接口
 */
class MyChild : IMe {
    override fun bar() {
        println("bar")
    }
}

fun t_mychild() {
    val myChild = MyChild()
    myChild.bar()
    myChild.foo()
}

/**
 * 接口中的属性
 * 接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性
 */
interface INewMe {
    // 抽象属性
    var name: String
}

class NewMeImpl : INewMe {
    // 重写属性
    override var name: String = "runoob"
}

fun t_new_me() {
    val meImpl = NewMeImpl()
    println("name = ${meImpl.name}")
}

/**
 * 函数的重写
 * 实现多个接口时,可能会遇到同一方法继承多个实现的问题
 */
interface A_1 {
    fun foo() {
        println("A_1")
    }

    fun bar()
}

interface B_1 {
    fun foo() {
        println("B_1")
    }

    fun bar() {
        println("B_1 bar")
    }
}

class C_1 : A_1 {
    override fun bar() {
        println("C_1 bar")
    }

}

class D_1 : A_1, B_1 {
    override fun bar() {
        println("D_1 bar")
        super<B_1>.bar()
    }

    override fun foo() {
        println("D_1 foo")
        super<A_1>.foo()
        super<B_1>.foo()
    }
}

fun t_o_method() {
    val d_1 = D_1()
    d_1.foo()
    d_1.bar()
}

/**
 * 实例中接口 A 和 B 都定义了方法 foo() 和 bar(), 两者都实现了 foo(), B 实现了 bar()。因为 C 是一个实现了 A 的具体类,
 * 所以必须要重写 bar() 并实现这个抽象方法。

  然而,如果我们从 A 和 B 派生 D,我们需要实现多个接口继承的所有方法,并指明 D 应该如何实现它们。
  这一规则 既适用于继承单个实现(bar())的方法也适用于继承多个实现(foo())的方法。
 */
/* -------------- 接口 -------------- */
fun main(args: Array<String>) {
    t_mychild()
    t_new_me()
    t_o_method()
}

扩展

package com.example.ext

/* -------------- 扩展 -------------- */
/**
 * kotlin可以对一个类的属性和方法进行扩展,且不需要使继承或使用Decorator模式
 * 扩展是一种静态行为,对于被扩展的类代码本身不会造成任何影响
 */

/**
 * 扩展函数
 * 扩展函数可以在已有的类中添加新的方法,不会对原类做修改
 * fun receiverType.functionName(params){
 *   body
 * }
 *
 * receiverType 要扩展的类
 * functionName 方法名称
 */

class New_User(var name: String)

// 扩展函数
fun New_User.Print() {
    println("User .. $name")
}

fun t_user_print() {
    val user = New_User("zz")
    user.Print()
}

/**
 * 为MutableList添加一个swap函数,交换不同位置的值
 */
fun MutableList<Int>.swap(_i: Int, _j: Int) {
    var tmp = this[_i]
    this[_i] = this[_j]
    this[_j] = tmp

    // this关键字指代接收者对象(receiver object)(也就是调用扩展函数时, 在点号之前指定的对象实例)。
}

fun t_change_item() {
    val l = mutableListOf(1, 2, 3)
    l.swap(0, 2)
    println(l.toString())
}


/**
 * 扩展函数是静态解析的
扩展函数是静态解析的,并不是接收者类型的虚拟成员,在调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,
而不是动态的类型决定的:
 */

open class EC

class ED : EC()

fun EC.foo() = "c" // 扩展函数foo

fun ED.foo() = "d" // 扩展函数foo

/**
 * 无论方法传递的是哪个实例,最终只会调用EC的扩展函数
 */
fun printFoo(c: EC) {
    // 类型是c类型
    // c
    println(c.foo())
}

fun t_ext_method_2() {
    // 这里会走EC的扩展函数
    printFoo(ED())

    // 这里才会走ED的扩展函数
    println(ED().foo())
}

/**
 * 若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。
 */
class NC {
    fun foo() {
        println("成员函数")
    }
}

fun NC.foo() {
    println("扩展函数")
}

fun t_ext_method_3() {
    val nc = NC()
    nc.foo()
}

/**
 * 扩展一个空对象
在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数
 */
fun Any?.toString(): String {
    if (this == null)
        return "null"
    // 空检测之后,this自动转换为非空类型,所以下面的toString
    // 解析为Any类的成员函数
    return toString()
}

fun t_ext_nul_obj() {
    var t = null
    println(t.toString())
}

/**
 * 扩展属性
除了函数,Kotlin 也支持属性对属性进行扩展:

扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。初始化属性因为属性没有后端字段(backing field),所以不允许被初始化,只能由显式提供的 getter/setter 定义。

val Foo.bar = 1 // 错误:扩展属性不能有初始化器
扩展属性只能被声明为 val。
 */
val <T> List<T>.lastIndex: Int
    get() = size - 1


/**
 *
伴生对象的扩展
如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数和属性。

伴生对象通过"类名."形式调用伴生对象,伴生对象声明的扩展函数,通过用类名限定符来调用
 */
class MyCls {
    companion object {
        // 将称为Companion
    }
}

// 扩展函数
fun MyCls.Companion.foo() {
    println("伴随对象的扩展函数")
}

// 扩展字段
val MyCls.Companion.no: Int
    get() = 10

fun t_ext_companion() {
    println("no: ${MyCls.no}")
    MyCls.foo()
}


/**
 * 扩展的作用域
 * 通常扩展函数或属性定义在顶级包下:

package foo.bar

fun Baz.goo() { …… }

要使用所定义包之外的一个扩展, 通过import导入扩展的函数名进行使用:

package com.example.usage

import foo.bar.goo // 导入所有名为 goo 的扩展
// 或者
import foo.bar.*   // 从 foo.bar 导入一切

fun usage(baz: Baz) {
baz.goo()
}
 */

/**
 * 扩展声明为成员
在一个类内部你可以为另一个类声明扩展。

在这个扩展中,有个多个隐含的接受者,其中扩展方法定义所在类的实例称为分发接受者,而扩展方法的目标类型的实例称为扩展接受者。
 */
// 扩展接受者
class EN_D {
    fun bar() {
        println("EN_D bar")
    }
}

// 分发接受者
class EN_C {
    fun baz() {
        println("EN_C baz")
    }

    fun EN_D.foo() {
        println("EN_C ext foo")
        bar()
        baz()
    }

    fun caller(d: EN_D) {
        println("EN_C caller")
        // 调用扩展函数
        d.foo()
    }
}

fun t_ext_mem() {
    println("t_ext_mem")
    val c: EN_C = EN_C()
    val d: EN_D = EN_D()
    c.caller(d)
}

/**
 * 假如在调用某一个函数,而该函数在分发接受者和扩展接受者均存在,则以扩展接收者优先,
 * 要引用分发接收者的成员你可以使用限定的 this 语法。
 */
class END {
    fun bar() {
        println("END bar")
    }
}

class ENC() {
    fun bar() {
        println("ENC bar")
    }

    fun END.foo() {
        println("ENC foo")
        // 调用END.bar(),扩展接收者优先
        bar()
        this@ENC.bar() // 调用ENC.bar
    }

    fun caller(d: END) {
        println("ENC caller")
        // 调用扩展函数
        d.foo()
    }
}

fun t_ext_mem_2() {
    println("t_ext_mem_2")
    val enc = ENC()
    val end = END()
    enc.caller(end)
}

// 调用 ->> 分发接收者 ->> 扩展接收者

/**
 * 以成员的形式定义的扩展函数, 可以声明为 open , 而且可以在子类中覆盖. 也就是说, 在这类扩展函数的派 发过程中,
 * 针对分发接受者是虚拟的(virtual), 但针对扩展接受者仍然是静态的。
 */
open class EN2D {

}

class N2D : EN2D() {

}

open class EN2C {
    open fun EN2D.foo() {
        println("EN2D.foo in EN2C")
    }

    open fun N2D.foo() {
        println("N2D.foo in EN2C")
    }

    fun caller(d: EN2D) {
        println("EN2C caller")
        // 调用扩展函数
        d.foo()
    }
}

class N2C : EN2C() {
    override fun EN2D.foo() {
        println("EN2D.foo in N2C")
    }

    override fun N2D.foo() {
        println("N2D.foo in N2C")
    }
}

fun t_ext_mem_3() {
    println(" t_ext_mem_3 ")
    println(" -------------- ")
    EN2C().caller(EN2D()) // EN2D.foo in EN2C
    println(" -------------- ")
    N2C().caller(EN2D()) // EN2D.foo in N2C
    println(" -------------- ")
    EN2C().caller(N2D()) // EN2D.foo in EN2C
}

class MyNewCls {
    companion object {
        val mFid1: Int = 1
        var mFid2 = "this is myCFid2"

        fun companionFun1() {
            println("MyNewCls this is 1st companion func")
            foo()
        }

        fun companionFun2() {
            println("MyNewCls this is 2st companion func")
            companionFun1()
        }
    }

    fun MyNewCls.Companion.foo() {
        println("MyNewCls 伴随对象的扩展函数 (内部) ")
    }

    fun test2() {
        println("MyNewCls test2 ")
        MyNewCls.foo()
    }

    init {
        println("MyNewCls init ")
        test2()
    }
}

val MyNewCls.Companion.no: Int
    get() = 10

fun MyNewCls.Companion.foo() {
    println("MyNewCls.Companion foo 伴随对象外部扩展函数")
}

fun t_ext_mem_4() {
    println("t_ext_mem_4")
    println("no: ${MyNewCls.no}")
    println("filed1:${MyNewCls.mFid1}")
    println("filed2:${MyNewCls.mFid2}")
    MyNewCls.foo()
    MyNewCls.companionFun2()
}

/* -------------- 扩展 -------------- */

fun main(args: Array<String>) {
    t_user_print()
    t_change_item()
    t_ext_method_2()
    t_ext_method_3()
    t_ext_nul_obj()
    t_ext_companion()
    t_ext_mem()
    t_ext_mem_2()
    t_ext_mem_3()
    t_ext_mem_4()
}

数据类和密封类

/* -------------- 数据类 -------------- */
/**
kotlin可以创建一个只包含数据的类:data
data class User(val name:String,val age:Int)

编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:
equals() / hashCode()
toString() 格式如 "User(name=John, age=42)"
componentN() functions 对应于属性,按声明顺序排列
copy() 函数

如果这些函数在类中已经被明确定义了,或者从超类中继承而来,就不再会生成。
为了保证生成代码的一致性以及有意义,数据类需要满足以下条件:

主构造函数至少包含一个参数。
所有的主构造函数的参数必须标识为val 或者 var ;
数据类不可以声明为 abstract, open, sealed 或者 inner;
数据类不能继承其他类 (但是可以实现接口)。
 */

/**
 * 复制
复制使用 copy() 函数,我们可以使用该函数复制对象并修改部分属性
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
 */
data class Account(val name: String, val age: Int)

fun t_data() {
    var jack = Account(name = "Jack", age = 1)
    // 复制并修改部分属性
    val olderJack = jack.copy(age = 2)
    println(jack)
    println(olderJack)
}

/**
 * 数据类以及解构声明
 * 组件函数允许数据在解构声明中使用
 */
fun t_data_dec_con() {
    val jane = Account("jane", 35)
    val (name, age) = jane
    println("$name , $age years of age") // jane , 35 years of age
}

/**
 * 标准数据类
标准库提供了 Pair 和 Triple 。在大多数情形中,命名数据类是更好的设计选择,因为这样代码可读性更强而且提供了有意义的名字和属性。
 */
/* -------------- 数据类 -------------- */

/* -------------- 密封类 -------------- */
/**
 * 密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:
 *  枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。
sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
 */
sealed class Expr

data class Const(val number: Double) : Expr()

data class Sum(val e1: Expr, val e2: Expr) : Expr()

/*
将类的声明和定义该类的单例对象结合在一起(即通过object就实现了单例模式)

即将class关键字替换为object关键字,来声明一个类,与此同时也声明它的一个对象。只要编写这么多代码,这个类就已经是单例的了

 换句话说,object declaration的类最终被编译成:一个类拥有一个静态成员来持有对自己的引用,并且这个静态成员的名称为INSTANCE,当然这个INSTANCE是单例的,故这里可以这么去使用。如果用Java代码来声明这个RepositoryManager的话,可以有如下代码:

class RepositoryManager{
    private RepositoryManager(){}
    public static final RepositoryManager INSTANCE = new RepositoryManager();

}

*/
object NotANumber : Expr()

// 使用密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。
fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

class ObjectOuter {
    object Inner {
        fun method() {
            println("I'm in inner class")
        }
    }
}

fun t_object_cls() {
    ObjectOuter.Inner.method()
}

/* -------------- 密封类 -------------- */
fun main(args: Array<String>) {
    t_data()

    t_data_dec_con()

    println("eval_1 ${eval(Const(35.0))}")
    println("eval_2 ${eval(Sum(Const(35.0), Const(35.0)))}")
    println("eval_2 ${eval(NotANumber)}")
    t_object_cls()
}
    原文作者:草蜢的逆袭
    原文地址: https://www.jianshu.com/p/d82382b533b4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞