Kotlin-类与对象:data数据类,object单例类,sealed密封类(第一行代码Kotlin学习笔记2)

类与对象

1.类

1.1定义类

可以使用如下代码定义一个类,以及声明它所拥有的字段和函数:

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

    fun eat() {
        println(name + " is eating. He is " + age + " years old.")
    }
}

然后使用如下代码创建对象,并对对象进行操作:

fun main() {
    val p = Person()
    p.name = "Jack"
    p.age = 19
    p.eat()
}

和java实例化方式类似,只是去掉类new关键字,之所以这么设计,是因为当你调用了某个类的构造函数时,你的意图只可能时对这个类的实例化。

1.2 继承

Kotlin中一个类默认是不可以被继承的,如果想要让一个类可以被继承,需要主动声明open关键字:

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

    fun eat() {
        println(name + " is eating. He is " + age + " years old.")
    }
}

要让另一个类去继承Person类,则需要使用冒号关键字:

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

为什么Person类后面要加上一对括号,详见:
Kotlin的面向对象编程,深入讨论继承写法的问题

2.接口

Java是但继承结构的语言,任何一个类最多智能继承一个父类,但可以实现任意多个接口,kotlin也是如此,Kotlin中定义接口的关键字和Java中是相同的,都是使用的interface:

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

而Kotlin中实现接口的关键字变量了冒号,和继承使用的是同样的关键字:

class Student(val name: String, val age: Int) : Person(name, age), Study {
    override fun readBooks() {
        println(name + " is reading.")
    }

    override fun doHomework() {
        println(name + " is doing homework.")
    }
}

和Java不同的是,Kotlin 的接口中定义的函数可以进行默认实现(Java 1.8之后也支持这个功能)

interface Study {
    fun readBooks()
    fun doHomework(){
		println("do homework default implementation.")
	}
}

3.修饰符

  • private:对当前类内部可见
  • public:与Java一致,表示对所有类可见,但在Kotlin中,public修饰符是默认项。而在Java中,default是默认项。
  • protected:Java中表示对当前类,子类和同一包路径下的类可见,在Kotlin中表示只对当前类和子类可见。
  • internal:Kotlin抛弃了Java中的default(同一包路径下的类可见),引入了internal,只对同一模块中的类可见。
修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected当前类,子类,同一包路径下类可见当前类,子类可见
default同一包路径下类可见(默认)
internal同一模块中的类可见

4.数据类与单例类

4.1 数据类data

Kotlin中使用data关键字可以定义一个数据类:

data class CellPhone(val brand:String, val price:Double) {
//    override fun equals(other: Any?): Boolean {
//        return super.equals(other)
//    }
}

Kotlin会根据数据类的主构造函数中的参数将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大简少了开发的工作量。

fun main() {
    val c1 = CellPhone("sam", 99.0)
    val c2 = CellPhone("sam", 99.0)
    println(c1)
    println("equals " + (c1 == c2))
}
//CellPhone(brand=sam, price=99.0)
//equals true

4.2 单例类object

在Java中实现单例类并不复杂: Java设计模式——单例模式.但在Kotlin中则更加简单,只需要将class关键字改为object关键字即可:

object Singleton {
    fun single(){
        println("------signle-----")
    }
}

而调用单例类中的函数比较类似于Java中静态方法的调用方式:

fun main() {
    Singleton.single()
}
//在java类中调用kotlin单例类
class JavaClass {
    public void javaTest(){
        Singleton.INSTANCE.single();
    }
}

这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例,并且保证全局只会存在一个Singleton实例。

4.3 密封类sealed

有时候我们会有这样的使用场景,先看代码:

interface Result {}
class Success(val msg:String):Result
class Failed(val error:Exception):Result
fun getResultMsg(result: Result) = when(result){
    is Success -> result.msg
    is Failed -> result.error.message
    else -> println("else")
}

此代码中,如果getResultMsg方法中我们不写else分支,编译器会认为我们when语句中缺少条件分支,会提示错误,但else语句却永远执行不到,但是当我们有另外一个类实现了Result接口时,如:

class WaitWait(val msg:String):Result
class Unknown(val msg:String):Result

如果getResultMsg方法中接收到的result实际类型为WaitWait或者Unknown时,最终只会执行else语句了,这样的代码既不健壮,又不合理。如果想要解决这个问题,就需要使用密封类了。密封类的关键字是sealed,使用也很简单,我们可以将Result接口修改为密封类的写法:

sealed class Result {}
class Success(val msg:String):Result()
class Failed(val error:Exception):Result()
class WaitWait(val msg:String):Result()
class Unknown(val msg:String):Result()
fun getResultMsg(result: Result) = when(result){
    is Success -> result.msg
    is WaitWait -> result.msg
    is Unknown -> result.msg
    is Failed -> result.error.message
}

这样在when语句中,我们也就不再需要使用else语句了,并且当when语句中传入一个密封类变量作为条件时,Kotlin编译器会自动检查该密封类有哪些子类,并强制要求你将全部子类都作为when语句的分支条件进行处理,否则会编译报错。这里需要注意的是:密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其它类中。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值