前面两篇文章简单介绍了对象的声明和一些控制流的用法,本文将对Kotlin中类的创建、属性、函数等方面做一个简单的介绍,也是自己学习后的一点心得
一、类
1、类的创建:
最基本的创建类和java中相同,修饰符+ 类名{}(
如果一个类没有类体,可以省略花括号)
class
Empty
class
Empty{
}
2、构造函数:在 Kotlin 中的一个类可以有一个主构造函数和一个或多个次构造函数
主构造函数:
class Person constructor(firstName: String) {
}
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
class Person(firstName: String) {
}
此时我们在创建对象时就可以直接初始化firstName:
var person = Person("Name")
此时实例化号person后,想通过person对象获取他的firstName属性,会发现掉不出他的属性,此时应将Person 的参数firName添加修饰符val/var,这两者的区别在之前已经区分过
class Person (var firstName : String){
}
var person = Person("Name")
person.firstName = "B"
3.次构造函数:
如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可,现添加第二个构造函数:
constructor(name :String , age :Int):this(name){ //直接委托主构造函数
this.age = age
}
创建第二个对象:
var personAge = Person("C",25)
Log.e("personAge", personAge.firstName)
Log.e("personAge", personAge.age.toString())
下面我们创建第三个构造函数通过第二个间接委托主函数:
constructor(name :String , age :Int,sex :String):this(name,age){
}
4、初始化代码块
初始化块中的代码实际上会成为主构造函数的一部分。委托给主构造函数会作为次构造函数的第一条语句,因此所有初始化块中的代码都会在次构造函数体之前执行。即使该类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块
我们在上面的类中添加一个代码块:
init {
Log.e("=====","这是初始化代码快")
}
constructor(name :String , age :Int):this(name){
Log.e("=====","这是次构造函数")
this.age = age
}
运行结果
主构造函数会调用代码块一次,次构造函数会把初始化代码块当成自己的第一条语句执行
5、类的继承
- 父类要有open修饰,否则为final类型不可继承
- kotlin中子类只可复写父类中开放的方法:用open修饰的方法
- 复写的方法 必须带 override
- 标记为 override 的成员本身是开放的,也就是说,它可以在子类中覆盖。如果你想禁止再次覆盖,使用 final 关键字:
6、覆盖方法
- 覆盖无默认参数的方法:
open fun sum(x:Int,y:Int)= x + y
创建一个Child类继承Person
class Child(firstName: String) : Person(firstName) {
override fun sum(x: Int, y: Int): Int {
return super.sum(2*x, 2*y)
}
}
创建child并调用sum方法:
var child = Child("Child")
var result = child.sum(2,3)
Log.e("=====", result.toString())//运行结果:10
- 覆盖有默认参数的方法:是使用与基类型方法相同的默认参数值。 当覆盖一个带有默认参数值的方法时,必须从签名中省略默认参数值:
在person中再添加一个有默认参数的方法:
open fun max(x :Int = 5,y:Int) = if (x > y) x else y
在child中的实现方法:
override fun max(x: Int , y: Int): Int { //省去默认值
return super.max(x, y)
}
调用:
child.max(y =10)//这个地方写 y = 10 之后再解释
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的
super
,如
super<Base>
:
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // 接口成员默认就是“open”的
fun b() { print("b") }
}
class C() : A(), B {
// 编译器要求覆盖 f():
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f()
}
}
8、函数调用
- 子类调用父类 使用super
class Child(firstName: String) : Person(firstName) {
override fun sum(x: Int, y: Int): Int {
return super.sum(2*x, 2*y)
}
}
上述创建的子类Child 调用父类的sum方法 super.sum()
- 子函数的内部类 调用 父类函数
现在我们在Child类中创建内部类Son
inner class Son{
fun sum_son(): Int{
return super@Child.sum(2,3)
}
}
调用sum_son方法:
var son = Child("A").Son()
Log.e("=====", son.sum_son().toString())
输出结果为:02-02 13:24:32.128 13678-13678/com.example.administrator.kotlinpractise E/=====: 5
9、覆盖属性:
在超类中声明然后在派生类中重新声明的属性必须以 override 开头,并且它们必须具有兼容的类型。
你也可以用一个 var 属性覆盖一个 val 属性,但反之则不行
open val boolean : Boolean = true
在child中
override val boolean: Boolean
get() = super.boolean