我爱编程

kotlin学习第三天

2018-08-08  本文已影响0人  千里重

运算符重载

kotlin中每一个运算符对应一个方法。比如我们想把两个对象加起来的话,只需要把“+”对应的方法复写就可以实现了。运算符对应的方法可以通过kotlin官网http://kotlinlang.org/docs/reference查询。

fun main(args: Array<String>) {
    val p1 = Person()
    val p2 = Person()
    p1.age = 10
    p2.age = 20
    //求p1和p2的年龄和
    var plus = p1.plus(p2)
    println(plus)
}
//重写“+”方法
class Person {
    var name = "张三"
    var age = 0

    fun plus(person: Person): Int {
        return age + person.age
    }
}

类的成员

类成员可以访问并且修改,kotlin的类成员变量默认已经实现了get以及set方法。

成员的访问与修改

由于kotlin的类成员变量默认实现get以及set方法,所以类中的成员可以直接调用:

fun main(args: Array<String>) {
    val stu = Student()
    println(stu.age)
    println(stu.name)
}

class Student {
    val name = "张三"
    val age = 15
}

修改类成员的可见性

在Kotlin中,若是想要类成员对于外界只能访问不能修改,则在类成员后中写入 private set。若想类成员对外界既不能访问也不能修改,则在类成员前写入private:

class Student {
    var name = "张三"
    private set//外界无法修改name
    private var age = 15//外界无法访问、修改age
}

自定义访问器

在我们的例子中,学生的年龄不可能随意设置,比如学生是-1岁,所以需要对设置的数据进行判定,符合一定要求后才能修改。对于此类要求,我们可以用自定义访问器field:

fun main(args: Array<String>) {
    var person = Student()
    println(person.age)//20
    person.age = 35//由于35>30,所以设置失败
    println(person.age)//20

}

class Student {
    var name = "张三"
    var age = 20
        set(value) {//value对应传递的age值
            if (value > 18 && value < 30) {
                //可以通过field表示这个字段
                field = value
            }
        }
}

主构函数和次构函数

主构函数

kotlin中主构函数即构造函数,但是无法直接访问构造函数中的元素。如果想要在构造函数里面实现一些操作,需要把代码写在init里:

fun main(args: Array<String>) {
    val p1 = Person("张三", 23)
    val p2 = Person("李四", 25)
    val p3 = Person("王五", 40)
    println(p1.age)//23
    println(p2.age)//25
    println(p3.age)//40
}

class Person(name: String, age: Int) {
    var name = ""
    var age = 0

    init {
        this.age = age
        this.name = name
    }
}

var和val在主构函数参数中的作用

主构函数参数使用var和val,相当于帮我们定义了字段,参数可以直接使用。参数没有var和val修饰,参数在其他地方不能使用 。参数有var修饰,可以使用,也可以修改 。参数有val修饰,只能使用,不能修改 :

fun main(args: Array<String>) {
    val p1 = Person("张三", 23)
    val p2 = Person("李四", 25)
    val p3 = Person("王五", 40)
    println(p1.age)
    println(p2.age)
    println(p3.age)
}

class Person(val name: String,val age: Int)

次构函数

次构函数必须要调用主构函数,必须要把参数传递给主构函数,且需要用constructor关键字:

class Person2(val name: String,val age: Int){
    constructor(name: String, age: Int,phone:String):this (name,age)//调用主构函数将参数传递给主构函数
}

次构函数间调用

次构函数可以直接调用主构函数,也可以通过调用次构函数来间接调用主构函数:

class Person3(name:String,age: Int){
    //调用主构函数
    constructor(name:String,age: Int,phone: String):this(name,age)
    //通过调用次构函数来间接调用主构函数
    constructor(name:String,age: Int,phone: String,qq:String):this(name,age,phone)
}

次构函数参数使用

构造函数加var和val只能在主构函数里面加,次构函数中不能加。主构函数参数可以直接加上var和val使用,次构函数只能够自己定义变量进行保存。

class Person3(val name:String,val age: Int){
    var phone = ""
    var qq = ""
    constructor(name:String,age: Int,phone: String):this(name,age)
    constructor(name:String,age: Int,phone: String,qq:String):this(name,age,phone){
        this.phone = phone
        this.qq = qq
    }
}

继承

继承是指一个对象直接使用另一对象的属性和方法。kotlin的继承和java中的继承大体相同,但需要注意以下几点:

1.需要将父类加上open关键字

2.需要加上():

kotlin的成员函数和成员变量对应的get以及set方法都有final修饰,不能进行继承,所以要在成员函数和成员变量前加上open关键字才能进行复写:

open class father() {
    open var name = "小头爸爸"
    open var age = 40
    open fun sayHello() {
        println("老哥 早上好")
    }

}

class son : father() {
    override var name: String = "大头儿子"
    override var age: Int = 14
    override fun sayHello() {
        println("同学 早上好")
    }

}

构造函数的继承

构造函数的继承除了通常的操作外,子类也需要构造函数,并且应能在父类中找到对应的字段,还需将函数传给父类。子类也可以用父类的字段:

fun main(args: Array<String>) {
    var p = Person("张三", 30)
    var s = Student("李四", 20, "男")
    println(p.age)//30
    println(s.sex)//男
    println(s.name)//李四

}

open class Person(var name: String, var age: Int) {
    open fun morning() {
        println("早上好")
    }
}

class Student(name: String, age: Int, var sex: String) : Person(name, age) {
    override fun morning() {
        println("晚上好")
    }
}

抽象类和抽象方法

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。包含抽象方法的类就是抽象类。抽象类不需要open关键字就可以被调用。

//人类 (抽象类)
abstract class Human {
    abstract var color: String
    abstract var language: String
    abstract fun eat()
}

//具体实现类
class Chinese : Human() {
    override var color: String = "yellow"
    override var language: String = "chinese"

    override fun eat() {
        println("用筷子吃饭")
    }
}

class USHuman : Human() {
    override var color: String = "white"
    override var language: String = "english"

    override fun eat() {
        println("用刀叉吃饭")
    }
}

class AfHuman : Human() {
    override var color: String = "black"
    override var language: String = "葡萄牙语"

    override fun eat() {
        println("用手吃饭")
    }
}

接口

接口的实现是在括号后面加个冒号,然后写上要实现的接口,不需要写interface。若是多个接口,就用逗号“,”隔开。

class men() : bike {
    override fun rideBike() {
        println("人骑车")
    }

}

interface bike {
    fun rideBike()
}

注意事项

1.java中接口中的字段一定要被赋值,但是Kotlin接口里的字段不能被赋值

2.java接口里面方法不能实现,kotlin可以实现

class men() : Bike, Drive {
    override val license: String = "123456"
    override fun drive() {
        println("人开车")
    }
    override fun rideBike() {
        println("人骑车")
    }

}

interface Bike {
    fun rideBike()
}

interface Drive {
    val license: String
    fun drive() {
        println("放手刹,踩油门,走")
    }
}

多态

同种功能的不同表现形式。kotlin中的多态原理同java:

abstract class Animal {
    abstract var name: String

    open fun bark() {
        println("动物叫")
    }
}

class Dog : Animal() {
    override var name: String = "旺财"

    override fun bark() {
        println("旺财  汪汪叫")
    }
}

class Cat : Animal() {
    override var name: String = "汤姆"

    override fun bark() {
        println("汤姆  喵喵叫")
    }
}

智能类型转换

在多态中,多个子类可能均与父类有差别。kotlin中可以通过智能类型推断来判断调用的字段所属于的子类,最终调用所属子类的方法。将父类引用转为子类引用,转换之前还需要判断是否是当前子类类型。一旦判断出是这个类型之后,编译器就把类型转换过去了,不需要手动转换。

fun main(args: Array<String>) {
    val shepHerdDog: Dog = ShepHerdDog()//将父类引用转为子类引用
    //判断是否是当前子类类型
    if (!(shepHerdDog is ShepHerdDog)) return
    //编译器自动转换
    shepHerdDog.shepHerd()
}

abstract class Dog

class ShepHerdDog : Dog() {
    fun shepHerd() {
        println("牧羊犬开始放羊了...")
    }
}

嵌套类、内部类

嵌套类默认都是static修饰的,属于静态类,不依赖于外部的环境,即和外部类没有关系:

fun main(args: Array<String>) {
    val inClass = outClass()
}

class outClass {
    var name: String = "李四"

    class inClass {
        fun say() {
            println(name)
        }
    }
}

内部类需要通过Inner修饰,且需要先创建出来外部环境:

fun main(args: Array<String>) {
    val inClass = outClass.inClass()
}

class outClass {
    var name: String = "李四"
    inner class inClass {
        fun say() {
            println(name)
        }
    }
}

内部类中使用this

如上例,若内部类中也有一个var name = "张三",则默认情况下会打印张三,即从最近开始找。如果我们想访问外部类中的name,也就是李四。这时候就需要把打印内容改为外部类名.this.namethis@outClass.name:

class OutClass {
    var name = "李四"

    inner class InClass {
        var name = "张三"
        fun sayHello() {
            println(this@OutClass.name)
            //或
            println(OutClass.this.name)
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读