一、类
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类后面要加上一对括号呢?
这就牵扯到了Java继承特性中的一个规定:子类中的构造函数必须调用父类中的构造函数。
这个规定在Kotlin中也要遵守。
那么再来回头看一下Student类,现在我们声明了一个主构造函数,根据继承特性的规定,子类的构造函数必须得调用父类的构造函数,可是主构造函数并没有函数体,我们怎样去调用父类的构造函数呢?
有的朋友可能会说,在init结构体当中去调用不就好了,这或许是一种办法,但却绝对不是一种好办法,因为绝大多数的场景我们都是不需要编写init结构体的。
Kotlin当然没有采用这种设计,而是用了另外一种简单但是可能不太好理解的设计方式:括号。子类的主构造函数调用父类中的哪个构造函数,通过在父类的后面加上括号来指定。
class Student(val sno: String, val grade: Int) : Person() {
}
在这里,Person类后面的一对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数,即使在无参数的情况下,这对括号也不能省略。
二、接口
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.")
}
}
三、修饰符
private:对当前类内部可见。 public:与Java一致,表示对所有类可见,但在Kotlin中,public修饰符是默认项。而在Java中,default是默认项。 protected:Java中表示对当前类,子类和同一包路径下的类可见,在Kotlin中表示只对当前类和子类可见。 internal:Kotlin抛弃了Java中的default(同一包路径下的类可见),引入了internal,只对同一模块中的类可见。
| 修饰符 | Java | Kotlin |
|---|---|---|
| public | 所有类可见 | 所有类可见(默认) |
| private | 当前类可见 | 当前类可见 |
| protected | 当前类,子类,同一包路径下类可见 | 当前类,子类可见 |
| default | 同一包路径下类可见(默认) | 无 |
| internal | 无 | 同一模块中的类可见 |