在 Kotlin 中,类使用 class 关键字来声明,类声明一般由类名、类头(指定了类型的参数、主构造方法)以及使用 {} 包起来的类体,类体可为空:
// 无构造方法的类
class Demo{
}
当只有一个构造方法时,一般写在类名后面,多个构造方法时,在类名后面的构造方法为主构造方法,如果主构造方法没有任何注解或者可见性修饰符,可以省略 constructor 关键字:
class Demo constructor(name:String) {
}
// 或者
class Demo (name:String) {
}
主构造方法不能包含任何的代码,初始化的代码要放到 init{} 代码块中,如果有多个 init{} 代码块,按顺序执行:
class Demo (name:String) {
init {
println("$name A")
}
init {
println("$name B")
}
}
// Kotlin 中 main() 默认是新建立一个文件专门跑 main() 方法
fun main(args: Array) {
Demo("name")
}
结果:
如果有主构造方法在类名后面,新的构造方法需要委托给主构造方法,可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可:
class Demo (name:String) {
constructor(name: String,age:Int):this(name){
println("name:$name,age:$age")
}
}
// Kotlin 中 main() 默认是新建立一个文件专门跑 main() 方法
fun main(args: Array) {
Demo("李四",20)
}
结果:
主构造方法是默认 public 的,如果你想你的构造方法私有化,只需要在 constructor 前面设置 private:
Any
并不是 java.lang.Object。
尤其是,它除了 equals()
、hashCode()
和 toString()
外没有任何成员)在 Kotlin 中,要想类可以被继承,需要使用 open 关键字,该关键字与 Java 中的 final 相反,它允许该类可以被继承,可以说,Kotlin 中的类默认是 final 的:
open class Father(lastName:String)
class Son(lastName: String):Father(lastName)
当父类有主构造参数时,子类必须要有主构造参数:
open class Father(lastName:String){
init {
println("lastName of Father:$lastName")
}
fun show(){
println("Hello")
}
}
class Son(lastName: String):Father(lastName){
init {
println("lastName of Son:$lastName")
}
}
fun main(args: Array) {
Son("HHHH").show()
}
结果:
当父类没有主构造方法时,有次构造方法,子类需要使用 super 关键字:
open class Father{
constructor(lastName:String){
println("lastName of Father:$lastName")
}
fun show(){
println("Hello")
}
}
class Son:Father{
constructor(lastName: String):super(lastName){
println("lastName of Son:$lastName")
}
}
fun main(args: Array) {
Son("HHHH").show()
}
结果:
open class Father{
open fun show(){
println("I'm Father !")
}
}
class Son: Father() {
override fun show() {
println("I'm Son !")
}
}
fun main(args: Array) {
Father().show()
Son().show()
}
结果:
因为 override 关键字就表示该方法是可以覆盖的,要想它不能被覆盖,就需要添加一个 final 关键字:
这样的话 show() 方法就不能被覆盖了。
open class Father {
open val name = "Father"
}
class Son:Father(){
override val name = "Son"
}
fun main(args: Array) {
println(Father().name)
println(Son().name)
}
结果:
你也可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质上声明了一个 getter() 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter() 方法。
open class Father(lastName:String) {
val a = lastName.length
open val name = "Father"
init {
println("$name:$lastName + $a")
}
}
class Son(lastName: String):Father(lastName){
override val name = "Son"
init {
println("${super.name}:$lastName")
}
init {
println("$name:$lastName")
}
}
fun main(args: Array) {
Son("张")
}
结果:
由结构可以看到:会先初始化父类,在父类的构造函数执行时,其非 open 属性也被初始化,而 open 属性未被初始化,所有会出现 null:张 + 1,接着才会初始化父类的 open 属性,所有子类就可以使用了,接着会初始化子类的构造方法。所以当我们设计一个父类时,应该避免在构造函数、属性初始化器以及 init 块中使用 open 成员。
open class Father{
open fun show(){
println("Father")
}
}
open class Son:Father(){
override fun show() {
super.show()
println("Son")
}
}
fun main(args: Array) {
Son().show()
}
结果:
而在 Kotlin 的内部类中,可以使用 @ClassA.x() 来调用 ClassA 的父类的 x() 方法:
open class Father{
open fun show(){
println("Father")
}
}
open class Son:Father(){
override fun show() {
super.show()
println("Son")
}
inner class GrandSon{
fun g(){
[email protected]()
}
}
}
class GrandSon:Son(){
override fun show() {
super.show()
println("Son")
}
inner class GrandSon1{
fun g(){
[email protected]()
}
}
}
fun main(args: Array) {
Son().show()
println("Son 的内部类:")
Son().GrandSon().g()
println("GrandSon 的内部类:")
GrandSon().GrandSon1().g()
}
结果:
open class Father{
open fun show(){
println("I'm Father")
}
}
// 接口是默认 open 的
interface Mother{
// 接口的方法也是默认 open 的
fun show(){
println("I'm Mother")
}
}
// 和 Java 一样,Kotlin 的类只能继承一个,接口可以继承多个
class Son:Father(),Mother{
override fun show() {
super.show()
super.show()
}
}
fun main(args: Array) {
Son().show()
}
结果:
abstract class Father{
abstract fun show()
}
class Son:Father(){
override fun show() {
println("hhhh")
}
}
fun main(args: Array) {
Son().show()
}
结果:
class Father{
companion object {
fun show(){
println("Hello")
}
}
}
fun main(args: Array) {
Father.show()
}
结果: