一、抽象类和接口

二、继承

三、类及其成员的可见性

四、object

五、伴生对象与静态成员

一、抽象类和接口

对于抽象类和接口的话,和Java还是挺像的,虽然有一些区别,但是基本用法还是相同的。

在项目开发过程中,我们常会用到回调来获取数据,我们先创建一个接口类

interface OnResultListener{
    fun success(value:Any);
    fun fail(errorCode:Int,error:String);
}

很眼熟,对不对。首先是interface关键字,表示上述代码是一个接口类,successfail分别是接口待实现的方法。我们创建一个NetOnResultListener,表示网络回调的类。

class NetOnResultListener:OnResultListener{
    override fun success(value: Any) {
    }

    override fun fail(errorCode: Int, error: String) {
    }
}

NetOnResultListener就是通过上面的方式继承了OnResultListener接口,并且通过关键字override实现了接口方法。其实接口也就这么多东西,下面我们说一下抽象类。项目中会经常用到控制器,所以我们先创建一个父类的控制器,如下:

abstract class BasePresenter {
    abstract fun setOnResultListener(onResultListener: OnResultListener)
}

这个控制器中只有一个抽象方法,OnResultListener就是上面写的接口类,每个控制器都会实现setOnResultListener方法。那如何使用子类继承呢?如下代码

class AccountPresenter: BasePresenter() {
    override fun setOnResultListener(onResultListener: OnResultListener) {
    }
}

看到和接口不一样的地方了吗?是的,继承的话,类名后面有一个括号,而接口的话并没有。当然Kotlin也是遵循单继承多实现的原则,也就是只能继承一个父类,但是可以实现多个接口,和Java是一样的。

二、继承

关于继承我就不在用语言去过多的描述了,了解Java的话,都知道继承是怎么回事。其实关于继承,上面的代码有介绍,看下面的代码

abstract class Person(open val age:Int) {
    abstract fun work();
}
class Doctor(age:Int):Person(age){
    override val age:Int = 10
    override fun work() {
        println("doctor is working , his age is $age")
    }
}
fun main(args: Array<String>) {
    val doctor:Doctor = Doctor(26)
    doctor.work()
}

Person类是一个父类,Doctor继承自Person。可以看到Person这个类有和方法前都有一个abstract关键字;如果想要覆写形参的话,参数名称前需要有一个open关键字,否则的话子类中的形参是不能被覆写的。如果父类是一个普通的类,不是抽象类怎么办呢?我们只需要将abstract关键字换成open即可,如下

open class Person(open val age:Int) {
    open fun work(){
    }
}

其实继承没有太多的东西可说的,主要就是上面这些。还有一些用法我们平时用的比较少,我就不在这里叙述了

三、类及其成员的可见性

Java中有四种修饰符:public  protected  default  private,这四种修饰符大家应该很清楚它们的用法。

Kotlin中也有四种修饰符:public  protected  internal  private

其中public  protected  private的用法和Java是相同的,但是有一点需要注意,Java中如果不写修饰符,默认为default修饰符,而Kotlin中默认的修饰符是public,这一点大家要记清楚哦

internal这个修饰符怎么用的?如果写过Android项目的话,大家应该知道,除了app目录以外,也可能会写其他的library,尤其是用了ARouter框架的,分包是肯定的。而internal这个修饰表示的就是:在某个module中使用。

四、object

Kotlin中的objectJava中的Object可有不一样的含义。Kotlin中的object是一个关键字,用来创建类。如下:

object A{
    fun a(){
        println("a 方法")
    }
}
fun main(args: Array<String>) {
    A.a()
}

看到上面的代码估计有的小伙伴就蒙了。object是静态的意思吗?其实不是,object有如下几个特点:

(1)被object修饰的类只有一个实例对象,类似于Java中的单例

(2)不能够自定义构造方法。因为类似于Java中的单例,所以唯一的构造方法也被私有了,不能自定义操作。

(3)可以和类一样来实现接口和继承父类

知道上面的特点就能明白为什么可以像上面的代码那么写了吧

五、伴生对象与静态成员

到这里,很多小伙伴会问,Kotlin中没有静态方法和属性吗,其实是有的,只是和Java中的静态表现形式不太一样。看下面的代码:

fun main(args: Array<String>) {
    StaticFun.staticFun1("字符串")
    StaticFun.staticFun2(3.0)
    println("i:${StaticFun.i}")
}

class StaticFun private constructor(){
    companion object{
        val i:Int = 50
        fun staticFun1(str:String){
            println("str:$str")
        }

        fun staticFun2(double:Double){
            println("double:$double")
        }
    }
}

上述代码的StaticFun这个类中的staticFun1staticFun2就是静态方法,i就是静态变量。看main方法中相应的使用和Java是一样的。我们看StaticFun这个类,首先constructor这个关键字前面有一个private,将构造方法变成了私有的;而静态方法staticFun1,staticFun2和静态变量i都写在了companion object这个代码块里。其实这个companin object产生的对象叫做伴生对象,和Java中的static用法差不多。如果在Java中引用Kotlin类的伴生对象和Kotlin这里的用法不太一样:

public class JavaMain {
    public static void main(String[] args) {
        StaticFun.Companion.staticFun1("字符串");
        StaticFun.Companion.staticFun2(3.0);
        System.out.println("i:"+StaticFun.Companion.getI());
    }
}

你会发现,类和静态成员之间有一个Companion,虽然可以正常使用,但是感觉有些别扭,那怎么办,我们简单修改一下StaticFun中的代码:

class StaticFun private constructor(){
    companion object{
        @JvmField
        public val i:Int = 50
        @JvmStatic
        fun staticFun1(str:String){
            println("str:$str")
        }
        @JvmStatic
        fun staticFun2(double:Double){
            println("double:$double")
        }
    }
}

仔细观察,i变量上面有一个@JvmField的注解,而静态方法上面有@JvmStatic的注解。这样修改之后再Java中去掉Companion就可以使用了