Kotlin面向对象编程

2020-09-19  本文已影响0人  code希必地

1、类与对象

Kotlin中类的声明和Java类一样,都是用关键字class来声明类

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

    fun introduce() {
        Log.e("TAG", "我的名字叫" + name + " 我已经" + age + "岁了")
    }
}

Person类已经定义完成,那如何创建Person类的对象呢?

 val p = Person()

和Java类似,只是剩去了new,这样也很好理解:Person()代表的是构造函数,而只有创建对象时才会调用构造函数,这样编码的意图也很明显就是创建对象。
接下来我们就能使用对象进行一些操作:

fun createPerson() {
        val p = Person()
        p.age=100
        p.name="张丹"
        p.introduce()
    }

2、继承与构造函数

open class Person{
}
class Student :Person() {
}

细心的你肯定也发现了Person后加了一对小括号,这又是为什么呢?这就和Kotlin中的主构造函数和次构造函数有关系了,

2.1、主构造函数

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

我们将学号和年级在主构造函数中声明了,所以在创建Student对象的时候就必须传入主构造函数中要求的所有参数。

class Student(val sno: String, val grade: Int) : Person() {
    init {
        //在创建Student对象时就会执行这个结构体
        Log.e("TAG","我是主构造函数,学号sno:"+sno+" 年级grade:"+grade)
    }
}
open class Person(val name: String, val age: Int) {
}

此时Student类肯定会报错,因为在Student类中我们指定调用父类的无参构造,而无参构造已经不存在了,必须给Person类传入name和age。可是在Student中并没有name和age,我们可以在Student中加入name和age

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

2.2、次构造函数

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

    init {
        Log.e("TAG", "我是主构造函数,学号sno:" + sno + " 年级grade:" + grade)
    }

    constructor(name:String,age:Int) : this("",0,name,age) {

    }

    constructor():this("",0){

    }

}
val stu1=Student("张无忌",50)
stu1.introduce()

val stu2=Student()
stu2.introduce()
        
val stu3=Student("10010",5,"尹力",130)
stu3.introduce()
class Teacher : Person {
    constructor(name: String, age: Int) : super(name, age) {
    }
}

注意这里代码的变化,Teacher类中没有显式的定义主构造函数并且定义了次构造函数,所以Teacher类是没有主构造函数,由于没有主构造函数,所以在继承Person类时也就不需要加扩号,原因很简单:由于Teacher类没有主构造函数,所以我们不能通过主构造函数来创建Teacher的实例,即使Kotlin允许此时添加括号,也是无法达到调用父类构造的目的。我们只能通过次构造函数创建实例,我们只能通过super来调用父类的构造函数。

3、接口

Kotlin中和Java一样都是单继承的,一个类只能继承一个父类,但是可以实现多个接口。和Java一样也是通过interface声明接口

interface Study {
    fun readBook()
    fun doHomeWork()
}

Student类实现Study的接口,并实现其中的方法

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

    init {
        Log.e("TAG", "我是主构造函数,学号sno:" + sno + " 年级grade:" + grade)
    }

    constructor(name: String, age: Int) : this("", 0, name, age) {

    }

    constructor() : this("", 0) {

    }

    override fun readBook() {
    }

    override fun doHomeWork() {
    }
}
interface Study {
    fun readBook(){
        Log.e("TAG","接口中的方法可以默认实现")
    }
    fun doHomeWork()
}

4、修饰符

在Kotlin中函数的可见性修饰符相比于Java变动还是很大的。直接上表

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

5、单例和数据类

5.1、数据类

数据类通常要重写equals()、hashCode()、toString()几个方法,其中eaquals()判断两个数据类是否相等,hashCode()作为eqauls()的配套方法,也需要重写否则会导致HashMap、HashSet中相关hash的操作不能正常工作,toString()是为了提供了一个清晰的日志输出,否则打印出来就是内存地址。下面举个简单的例子:

public class CellPhone {
    String brand;
    double price;

    public CellPhone(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof CellPhone) {
            CellPhone cellPhone = (CellPhone) o;
            return cellPhone.price == price && cellPhone.brand.equals(brand);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return brand.hashCode() + (int) price;
    }

    @Override
    public String toString() {
        return "CellPhone:brand:" + brand + " price:" + price;
    }
}

在Kotlin的实现上述功能就只需一句代码即可。

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

神奇的地方就在于data关键字,在Kotlin中的类声明了data关键字,那么这个类就是一个数据类,Kotlin中会根据主构造函数中的参数自动生成eqauls()、hashCode()、toString()等方法并实现相应的逻辑。另外在一个类中没有任何代码时,可以省了大括号
下面我们测试下该类

fun testDataClass() {
        val cellPhone1 = CellPhone("xiaomi", 2000.0)
        val cellPhone2 = CellPhone("xiaomi", 2000.0)
        Log.e("TAG", "cellPhone1:" + cellPhone1.toString()+"  cellPhone2:"+cellPhone2.toString()+"  cellPhone1.equals(cellPhone2):"+(cellPhone1==cellPhone2))
    }

输出:
cellPhone1:CellPhone(brand=xiaomi, price=2000.0)  cellPhone2:CellPhone(brand=xiaomi, price=2000.0)  cellPhone1.equals(cellPhone2):true

很明显CellPhone已经正常工作了。

5.2、单例类

在Java中的实现

public class SingleInstance {
    private static SingleInstance instance;

    private SingleInstance() {
    }


    public static synchronized SingleInstance getInstance() {
        if (instance == null) {
            instance = new SingleInstance();
        }
        return instance;
    }

}

在Kotlin中创建一个单例类很简单,只需要将class关键字改成object关键字即可。

object SingleInstance {
}

现在SingleInstance就是一个单例类了,我们可以直接在这个类中编写需要的函数,比如加入一个singleInstanceTest()

object SingleInstance {

    fun singleInstanceTest() {
        Log.e("TAG","singleInstanceTest is called")
    }
}

可以看到,Kotlin不需要私有化构造函数,也不需要提供getInstance()这样的静态函数,只需要将class修改为object,Kotlin就帮我们生成了单例类相关的逻辑,它的调用也很简单

SingleInstance.singleInstanceTest()

这种写法看上去像是静态方法的调用,其实Kotlin内部已经帮我们生成了SingleInstance实例,并且该实例有且仅有一个。

上一篇下一篇

猜你喜欢

热点阅读