安卓语言基础之Kotlin的面向对象编程

1,146 阅读5分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

前言

强大而灵活的RecyclerView Adapter——BRVAH(框架引入与BaseQuickAdapter使用篇) - 掘金 (juejin.cn)这篇文章中,我自定义了一个属性类,但其实当时我写的时候是恍惚了好一阵,因为习惯用Java语言开发安卓的我,一时不知道用Kotlin如何写类与其构造方法,异常尴尬,于是立刻翻出教程学习起来,然后才继续完成了这个Adapter的Demo,下面我们就来看看如何使用Kotlin完成面向对象编程吧!

image.png

正篇

类的写法

和Java一样的地方是都要用class关键字:

class Person {
    var name = ""
    var age = 0
    
    fun profile() {
        println("name : $name, age : $age")
    }
}

也是大括号里面写成员变量和成员方法,实例化也很简单:

val p = Person()

只是没有new这个关键字,这是Kotlin的机制。

继承

Kotlin的继承不需要写extends关键字,而且Kotlin的继承机制也与Java不一样,在Kotlin中任何一个非抽象类默认都是不可继承的,原因与val关键字类似,因为类和变量一样,最好不可变,如果一个类允许被继承,它就无法预知子类会如何实现,从而导致出现一些未知风险,所以当一个类不是用来继承的,在Java中也应该用final声明,禁止其继承。

而Kotlin已经主动帮我们做好了,它默认所有非抽象类都不可被继承,而抽象类是不能直接实例化,需要子类继承才能创建实例,所有抽象类就是必须要被继承才行。

但如果我们想要让一个类可以被继承,其实只需要加上关键字open即可:

open class Person {
    var name = ""
    var age = 0

    fun profile() {
        println("name : $name, age : $age")
    }
}

然后在Kotlin中Java的继承关键字extends变成了“:”(冒号):

class Teacher : Person() {
    var num = 0
    var className = ""
}

我们看到父类还加上了括号,这就是和下面要说的构造函数有关

构造函数

open class Person(
    val name : String,
    val age : Int
) {
    fun profile() {
        println("name : $name, age : $age")
    }
}

class Teacher(var num : Int,
              var className : String,
              name: String,
              age: Int
              ) : 
    Person(name, age) {
    
}

我们可以看到和Java的构造函数不同,它不是写在类方法体的,而是像方法声明参数一样写在类名后的小括号内,所以父类继承时也就需要小括号,同时我们将子类Teacher后的这个小括号内容称作主构造函数,任何一个类只能有一个主构造函数,当然,有主构造函数,也会有次构造函数,这里先不过多阐述,后面有时间再更新到本文中。

有构造函数的类实例化:

val teacher = Teacher(25, "A", "SchoolPerson", 30)

接口

Kotlin的接口和Java的接口声明类似:

interface Teach {
    fun teach()
    fun work()
}

继承后需要去实现接口的所有方法,继承不需要用Java的implements关键字,还是使用冒号,多个类时中间用逗号分开,接口不用名称后加小括号,因为它没有构造函数可调:

class Teacher(var num : Int,
              var className : String,
              name: String,
              age: Int
              ) :
    Person(name, age), Teach {
    override fun teach() {
        TODO("Not yet implemented")
    }

    override fun work() {
        TODO("Not yet implemented")
    }

}

其中,override为Kotlin重写方法的关键字,和Java的@Override注解类似

此外,Kotlin也支持接口函数默认实现,即可以在接口中对函数实现,然后在实现接口时就不用强制实现该函数,自由选择是否实现该函数,不实习就调用默认实现方法:

interface Teach {
    fun teach()
    //默认实现
    fun work() {
        println("Work!!")
    }
}

继承后可以选择对已经默认的work方法实现或不实现:

image.png

默认实现去除继承中的实现方法不报错:

image.png

未实现继承后也不实现的话会报错:

image.png

这种使用接口的编程方式也叫面向接口编程,亦称多态。

数据类

数据类通常用于将服务器端或数据库的数据映射到内存中,为编程逻辑提供数据模型的支持,我们常说的MVC,MVP,MVVM这些架构模式的M即指代数据类

前言中那个图片其实就是想写数据类但当时还不知道Kotlin如何写就导致出现了个四不像的,但也勉强符合预期,后面会进行更正,那么数据类该如何写呢,我之所以写错就是因为Java中数据类实在不一样,在Java中我们通常要重写equals()、hashCode()和toString()方法,让这个类拥有数据类的功能:

public class ModelDemo {
    String name;
    int age;

    public ModelDemo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ModelDemo)) return false;
        ModelDemo modelDemo = (ModelDemo) o;
        return age == modelDemo.age && Objects.equals(name, modelDemo.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "ModelDemo{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

而在Kotlin中,只要你加上关键字data就能自动帮你处理好这些,不需要做这些无用的工作:

data class ModelDemo(val name: String, val age: Int)

就这一句,简简单单。然后一样可以实现上面Java代码重写的方法的作用:

val modelDemo = ModelDemo("Name", 18)
val modelDemo1 = ModelDemo("Name", 18)
println(modelDemo)
println(modelDemo == modelDemo1)

image.png

单例类

首先我们了解一下单例模式:

单例模式,最常用、最基础的设计模式之一,可用于避免创建重复对象,在全局最多只能拥有一个实例。

单例模式的写法很多,我们这边先看一下Java的一种常见写法:

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

   public void singleDemoTest() {
        System.out.println("singleDemoTest is called");
   }
}

调用:

SingleDemo singleDemo = SingleDemo.getInstance();
singleDemo.singleDemoTest();

Java中看起来实现单例也不难,但当我看到Kotlin中时,真的笑了:

object SingleDemo {
}

对,这就是Koltin版的单例,如果再加上Java中实现的方法:

object SingleDemo {
    fun singleDemoTest() {
        println("singleDemoTest is called")
    }
}

调用看起来像在使用Java静态方法的调用,其实是Kotlin已经帮我们自动创建好了SingleDemo的实例,且会保证全局只存在一个SingleDemo实例:

SingleDemo.singleDemoTest()

只能说不愧是晚出来的语言,优势真明显,只需要把class关键字换成object,一个单例简简单单完成创建。

总结

本文将Kotlin的面向对象编程介绍了一遍,真的感受到了Kotlin的方便与优势,感谢大家的阅读!