Kotlin学习笔记(三)类和继承
2017-06-12 16:25
183 查看
提示:本文为作者阅读Kotlin中文站学习笔记,建议读者移步Kotlin中文站完整学习。
类
Kotlin中,使用class关键字生命一个类。类声明由类名,类头(指定其类型参数,主构造函数等)和大括号括起来的类体组成。
Kotlin中,一个类可以有一个主构造函数或和一个或多个次构造函数。主构造函数是类头的一部分,跟在类名(和可选的类型参数)后面,如果主构造函数没有任何注解或可见性修饰符,可以省略constructor关键字。
主构造函数不包含任何的代码,初始化代码可以放到init关键字修饰的初始化块中:
主构造函数中的参数可以在初始化块,或类体内声明的属性初始化器中使用:
也可以以下方式,声明属性及在主构造函数中初始化属性:
类也可以声明前缀有constructor的次构造函数,如果类有主构造函数,每个次构造函数都要委托给主构造函数,可以直接委托,也可以通过别的次构造函数间接委托。委托到同一个类中的另一个构造函数,用this关键字即可。
如果一个非抽象类没有声明任何(主,次)构造函数,Kotlin会生成一个不带任何参数的默认构造函数,可见性为public。
在 JVM 上,如果主构造函数的所有的参数都有默认值,编译器会生成 一个额外的无参构造函数,它将使用默认值。
在Kotlin中,没有new关键字,要创建一个类的实例,只需像调用普通函数一样,调用类的构造函数:
继承
Kotlin中所有的类都有一个共同的超累类Any,对于没有超类型声明的类是默认超类。Any类不是java.lang.Object类,它只有equals,hashCode(),toString()3个成员方法。
要显式声明一个超类,可以把类型放到类头的冒号之后,如果该基类有一个主构造函数,则其基类必须用主构造函数的参数就地初始化:
如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:
类上的 open 标注与 Java 中 final 相反,它允许其他类从这个类继承。默认情况下,在 Kotlin 中所有的类都是 final。
Kotlin力求清晰,需要显式标注可以覆盖的成员及覆盖后的成员。
B.f()函数必须加上override标注,否则会编译出错。如果A.f()没有加open标注,则子类中不允许定义相同签名的函数,不论加不加override。在一个final类(没有open标注的类),开放成员是禁止的。Kotlin中默认类是final的。
标记为override的成员本身是开放的,可以在子类中覆盖。如果你想禁止其在子类中继续被覆盖,可以加final关键字。
属性覆盖与方法覆盖类似,在超类中声明然后在派生类中重新声明的属性必须以override开头,并且必须具有兼容的类型。每个声明的属性可以由具有初始化器的属性或getter方法的属性覆盖。
我们可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。
我们也可以在主构造函数中使用 override 关键字作为属性声明的一部分。
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如
我们可以用abstract关键字定义抽象类和抽象方法,抽象方法不需要在本类实现,并且不需要用open关键字标注一个抽象类或抽象方法-因为这不言而喻。
类
Kotlin中,使用class关键字生命一个类。类声明由类名,类头(指定其类型参数,主构造函数等)和大括号括起来的类体组成。
class A public constructor(arg1:String){ }
Kotlin中,一个类可以有一个主构造函数或和一个或多个次构造函数。主构造函数是类头的一部分,跟在类名(和可选的类型参数)后面,如果主构造函数没有任何注解或可见性修饰符,可以省略constructor关键字。
class A (arg1:String){ }
主构造函数不包含任何的代码,初始化代码可以放到init关键字修饰的初始化块中:
class A (arg1:String){ //初始化块 init { //... } }
主构造函数中的参数可以在初始化块,或类体内声明的属性初始化器中使用:
class(arg1:String){ var s tr:String=arg1 //初始化块 init { print(arg1) } }
也可以以下方式,声明属性及在主构造函数中初始化属性:
class A (var arg1:String){ }
类也可以声明前缀有constructor的次构造函数,如果类有主构造函数,每个次构造函数都要委托给主构造函数,可以直接委托,也可以通过别的次构造函数间接委托。委托到同一个类中的另一个构造函数,用this关键字即可。
class A (var arg1:String){ constructor():this("")//次构造函数 }
如果一个非抽象类没有声明任何(主,次)构造函数,Kotlin会生成一个不带任何参数的默认构造函数,可见性为public。
在 JVM 上,如果主构造函数的所有的参数都有默认值,编译器会生成 一个额外的无参构造函数,它将使用默认值。
class A (var arg1:String=""){ }
在Kotlin中,没有new关键字,要创建一个类的实例,只需像调用普通函数一样,调用类的构造函数:
var a:A=A()//创建一个A的实例
继承
Kotlin中所有的类都有一个共同的超累类Any,对于没有超类型声明的类是默认超类。Any类不是java.lang.Object类,它只有equals,hashCode(),toString()3个成员方法。
要显式声明一个超类,可以把类型放到类头的冒号之后,如果该基类有一个主构造函数,则其基类必须用主构造函数的参数就地初始化:
class B constructor(arg: String):A(arg){ }
如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:
class MyView : View { constructor(ctx: Context) : super(ctx) constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) }
类上的 open 标注与 Java 中 final 相反,它允许其他类从这个类继承。默认情况下,在 Kotlin 中所有的类都是 final。
Kotlin力求清晰,需要显式标注可以覆盖的成员及覆盖后的成员。
open class A constructor(arg1:String){ open fun f():Unit{ } } class B :A(){ override fun f() { super.f() } }
B.f()函数必须加上override标注,否则会编译出错。如果A.f()没有加open标注,则子类中不允许定义相同签名的函数,不论加不加override。在一个final类(没有open标注的类),开放成员是禁止的。Kotlin中默认类是final的。
标记为override的成员本身是开放的,可以在子类中覆盖。如果你想禁止其在子类中继续被覆盖,可以加final关键字。
class B :A(){ final override fun f() { super.f() } }
属性覆盖与方法覆盖类似,在超类中声明然后在派生类中重新声明的属性必须以override开头,并且必须具有兼容的类型。每个声明的属性可以由具有初始化器的属性或getter方法的属性覆盖。
open class C { open val str: String get() = "Hello World!" } class D : C() { override var str: String get() = super.str set(value) { str = value } }
我们可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。
我们也可以在主构造函数中使用 override 关键字作为属性声明的一部分。
open class C { open val str: String get() = "Hello World!" } class D constructor(override val str: String): C() { }
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如
super<E>:
interface E{ fun f():Unit{ print("f in E") } } interface F{ fun f():Unit{ print("f in F") } } class D:E,F{ override fun f() { super<E>.f() super<F>.f() } }
我们可以用abstract关键字定义抽象类和抽象方法,抽象方法不需要在本类实现,并且不需要用open关键字标注一个抽象类或抽象方法-因为这不言而喻。
//抽象类 abstract class G{ abstract fun g()//抽象方法 } class H: G() { override fun g() { TODO("not implemented") } }
相关文章推荐
- Kotlin 学习笔记(2)类和继承
- Kotlin学习笔记--继承、接口、代理、委托、单例
- Android知识体系梳理笔记五:Kotlin学习笔记一:类和继承以及Anko(全)的基本使用
- Kotlin 学习笔记(三) 类和继承
- AS3.0基础学习笔记(6): 类继承
- C++学习笔记(19)——多继承中的虚函数
- Java构造函数的继承-Java 学习笔记 (14)
- javascript学习笔记(二)--继承
- C#2005 .NET3.0高级编程学习笔记————继承
- tij学习笔记 多态,继承
- C++学习笔记(7)——多基类继承的构造函数的调用
- java学习笔记5:对象继承upcasting
- 类的继承学习笔记
- ASP.NET控件开发学习笔记--第7回 从WebControl继承
- javascript学习笔记 (五) -继承和Closures
- C++学习笔记(8)——继承中的二义性问题和虚基类
- JAVA学习笔记之七继承和多态
- C#学习笔记(六):继承
- JavaScript中的继承学习笔记(1):Crockford uber方法中的陷阱
- Spring学习笔记之Bean定义继承