kotlin学习总结(二)

目录

四 类与对象

继承与构造函数

接口

函数的可见性修饰符

数据类和单例类


四 类与对象

在kotlin创建一个类的代码如下所示

class Person{
    var name=""
    var age=0
    fun eat(){
        print(name)
        print(age)
}

对这个类进行实例化的代码如下所示

val p=Person()

实例化的方法和Java基本类似,只是去掉了new关键字。上述代码中p就可以称为Person类的实例,也可以称为一个对象。可以对p对象进行一些操作,如下所示

p.name="jack"
p.age=10
p.eat()

上述代码将p对象的姓名赋值为Jack,年龄赋值为10,然后调用它的eat()函数,可以打印出这个人的姓名年龄的信息。

继承与构造函数

在kotlin中,任何一个非抽象类默认都是不可被继承的,相当于Java中给类声明了final关键字。如果想让上述的Person类被继承,必须在Person类的前面加上open关键字。如下所示

open class Person{
    ...
}

在Java中继承的关键字为extens,在kotlin中变成一个冒号,如下所示

class Student : Person(){
    var sno=""
    var grade=0
}

这里有一个小细节,那就是继承的时候在Person类后面加上一对小括号,而Java中的继承并不需要括号。这个括号涉及构造函数的知识。

任何一个面向对象的语言都会有构造函数的概念,在kotlin中,构造函数分成了两种,主构造函数和次构造函数。

主构造函数是最常见的构造函数。每个类都会默认有一个不带参数的主构造函数,当然也可以显式的给它指明参数。主构造函数的特点是没有函数体,直接定义在类名的后面即可。如下所示

class Student(val sno:String,val grade:Int):Person(){
    }

当将字段放进主构造函数的时候,要求在对该类实例化的时候,必须传入构造函数中要求的所有参数。如下所示

val student=Student("123",6)

如果想在主构造函数中编写一些逻辑,kotlin给我们提供了一个init结构体,如下所示

class Student(val sno:String,val grade:Int):Person(){
    init{
        print(sno)
        print(grade)
    }
}

在继承特性上,子类的构造函数必须调用父类的构造函数。观察上述代码,Student类声明的主构造函数必须调用父类的构造函数,但是这个时候我们发现父类的主构造函数并没有函数体。而kotlin采用了括号的方式实现了这一点,子类的主构造函数调用父类的哪个构造函数,在继承的时候通过括号来指定。因此这里表示Student类的主构造函数在初始化的时候会调用Person类的无参构造函数,即使在无参的时候,这对括号也不能省略。当然也可以修改Person的主构造函数,让它有参数。如下

open class Person(val name:String,val age:Int){
    ...
}

这个时候也必须改一下Student类的主构造函数,如下

class Student(val sno:String,val grade:Int,name:String,age:Int):
                Person(name,age){
    ...
}

这里有一个小细节,在子类的主构造函数中增加父类的字段的时候,不能在前面加val或者var关键字,因为在主构造函数中将参数声明成val或者var,那么这个参数会自动变成该类的字段。就会导致和父类中的同名字段冲突。那么现在就可以通过如下方式创建一个Student类的实例。

val student = Student("123",5,"Jack",10)

接下来kotlin中构造函数的另一个部分,次构造函数。任何类都只能有一个主构造函数,但是可以有多个次构造函数。次构造函数也可以用于实例化一个类,只不过它拥有函数体。当一个类既有主构造函数又有次构造函数的时候,所有的次构造函数都必须调用或间接调用主构造函数。如下代码

class Student(val sno:String,val grade:Int,name:String,age:Int):
                Person(name,age){
    constructor(name:String,age:Int):this("",0,age,name){}
    constructor():this("",0){}
    ...
}

kotlin中次构造函数是通过constructor关键字定义。第一个次构造函数接收name和age参数,通过this关键字调用主构造函数。将sno和grade参数赋值为初始值。第二个次构造函数不接受任何参数,通过this关键字调用第一个次构造函数,并将age和name也赋值为初始值。

还有一种比较特殊的情况,那就是类中只有次构造函数没有主构造函数,这在kotlin中也是允许的。当一个类没有显式的定义主构造函数并且定义了次构造函数,它就是没有主构造函数的,如下代码所示

class Student : Person {
    constructor(name:String,age:Int):super(name,age){}
}

在这里,Student类的后面没有显式的定义主构造函数,同时定义了次构造函数,所以现在Student类是没有主构造函数的,没有主构造函数,在继承Person的时候的时候也就不需要加上括号了。也由于没有主构造函数,次构造函数在调用父类构造方法的时候就不能使用this了,而是要使用super。

但是其实次构造函数几乎是用不到的,kotlin提供了一个给函数设定参数默认值的功能。如下代码

class Student(val sno:String=“”,val grade:Int=0,name:String=“”,age:Int=0):
                Person(name,age){
    ...
}

只需要在主构造函数中给每个参数都设置默认值,就可以使用任何传参组合来对Student类进行实例化。

接口

接口是用于实现多态编程的重要组成部分,Java是单继承结构的语言,一个类最多只能继承一个父类,但是却可以实现任意多个接口,kotlin也一样。kotlin中创建一个接口的关键字为interface,如下

interface Study{
    fun read()
    fun doHomework()
}

kotlin中实现接口的关键字和继承一样,也是冒号,但是实现接口不用加括号,因为它没有构造函数。如下

class Student(name:String,age:Int):Person(name,age),Study{
    override fun read(){
        print(name+"is read")
    }
    override fun doHomeWork(){
        print(name + "is doing homework")
    }
}

Study接口中定义了两个待实现方法,因此Student中必须实现接口中的函数。我们来调用一下这个接口中的两个方法。如下所示

fun main(){
    val student=Student("jack",10)
    doStudy(student)
}
fun doStudy(study:Study){
    study.read()
    study.doHomework()
}

首先我们创建一个Student的实例,这里是可以直接调用该实例的方法。由于Student类实现了Study接口,因此Student的实例,是可以传递给Study参数的然后调用Study接口的两个函数,如果传入的实例不一样,接口的函数展示的行为也不一样。这种叫面向接口编程,也叫多态。

Java在jdk 1.8 之后,允许对接口中定义的函数进行默认实现,kotlin也支持这一功能。当接口中的函数有了默认实现之后,当一个类去实现该接口时,就可以自由选择是否实现该函数。

函数的可见性修饰符

Java中的可见性修饰符有public,protected,private,default,kotlin中的可见性修饰符有public,protected,private,internal。它们之间的区别联系如下图所示。

修饰符 Java Kotlin
public 所有类可见 所有类可见(默认)
private 当前类可见 当前类可见
proteced 当前类、子类、同一包路径下可见 当前类,子类可见
default 同一包路径下可见(默认)
internal 同一模块中的类可见

数据类和单例类

数据类用于将服务器端或者数据库中的数据映射到内存中,为项目提供数据模型的支持。像MVVM的架构模式中的M就是数据类。在Java中,数据类需要重写equals()、hashcode()、toString()这几个方法。重写equals就必须重写hashcode,否则会导致hashmap等hash相关的系统类无法正常工作。但是在kotlin中只需要加上data关键字,如下所示

data class Cellphone(val brand:String,val price:Double)

当一个类中没有任何代码时,可以将大括号省略。

fun main(){
    val cell1=Cellphone("123",19)
    val cell2=Cellphone("123",19)
    println(cell1)
    println(cell1==cell2)
}

这里输出的结果应该是true,若没有data关键字,则得到不同的结果。

Java中的单例类实现并不是很复杂,如下代码

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public synchronized static Singleton getInstance(){
        if (instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}

而在kotlin中,只需要如下

object Singleton{
}

如果要调用单例类中的方法,只需要类名.方法名即可,类似Java中的静态方法的调用方式。但其实kotlin在背后自动创建了一个Singleton的实例,并且保证全局只会存在一个。

你可能感兴趣的:(kotlin)