类和对象

作者: Mobile_Joy | 来源:发表于2017-06-25 00:34 被阅读0次

    类和对象

    类和继承

    Kotlin中使用关键字class声明类

    class Person{
    }
    

    类的声明由类名类头(指定类的类型参数、主构造函数等)和类体(后面花括号包围的部分);如果一个类没有类体,可以省略花括号。

    class Person
    

    构造函数

    在Kotlin中一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数函数是类头的一部分:它跟着类名(和可选的类型参数)后。

    class Person constructor(firstName: String){
    }
    

    如果主构造函数没有任何的注解和可可见性修饰符,可以省略constructor关键字。

    class Person(firstName: String){
    }
    

    主构造函数不包含任何代码。初始化代码可以放在以init关键字作为前缀的初始化块(initializer block)中:

    class Customer(name: String) { 
        init {
            logger.info("Customer initialized with value ${name}") 
        }
    }
    

    注意主构造函数的参数可以在初始化块中使用。也可以在类体内声明属性时,在属性的初始化器中使用:

    class Customer(name: String){
        init{
            logger.info("Customer initialized with value ${name}") //在初始化块中使用主构造函数的参数
        }
        val customerKey = name.toUpperCase()//在属性的初始化器中使用主构造函数的惨是
    
    }
    

    其实,声明属性以及从主构造函数初始化属性,Kotlin有更简洁的语法:

    class Person(
        val firstName: String, 
        val lastName: String, 
        var age: Int) { 
            // ......
    }
    

    与普通在类内部声明的属性一样,主构造函数中声明的属性也可以是可变(var)或只读(val)。
    如果主构造函数有注解或可见性修饰符,则关键字constructor不能省略,并且修饰符在其前面:

    class Customer public @Inject constructor(name: String){
        //do some thing
    }
    

    次构造函数

    类也可是声明前缀有constructor次构造函数

    class Person{
        constructor(parent: Person){
            parent.chilren.add(this)
        }
    }
    

    如果类有主构造函数,每个次构造函数都需要委托给主构造函数,可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用this关键字即可:

    class Person(val name: String){
        constructor(name: String,parent: Person) : this(name){
            parent.children.add(this)
        }
    }
    

    如果一个类非抽象并且没有声明任何(主或次)构造函数,它会默认生成一个无参的主构造函数。并且这个默认无参构造函数的可见性为public。如果你不希望你的类有一个公有的构造函数,你需要声明一个带飞默认可见性的空主构造函数:

    class DontCreatMe private constructor(){
    }
    

    在JVM上,如果主构造函数的所有参数都有默认值,编译器会生成一个额外的无参构造函数,它将使用默认值,这使得Kotlin更易于使用像Jackson或JPA这样通过无参构造函数创建类的实例的库。

    class Customer(val customerName: String = "")
    

    创建类的实例

    要创建类的实例,我们只需要像调用普通函数一样调用构造函数:

    val user = User()
    val customer = Customer("Jon Smith")
    

    可以发现Kotlin中创建类的实例,是不需要new关键字的,Kotlin中也没有这个关键字

    类成员

    • 构造函数和初始化块
    • 函数
    • 属性
    • 嵌套类和内部类
    • 对象声明

    继承

    在Kotlin中所有类都有一个共同的超类Any,所有类都直接或间接派生自这个类,类似Java中的Object

    class Example (){//默认派生自Any
    }
    

    但是,Any并不是java.lang.Object;它除了equalshasCode()toString()外没有其它成员。
    要继承一个类,我们把超类放到派生类的类头的冒号后面:

    open class Base(p: Int)
    class Derived(p: Int) : Base(p)
    

    如果子类有一个主构造函数,其基类可以并且必须用子类主构造函数的参数就地初始化。
    若子类没有主构造函数,那么每个次构造函数必须使用super关键字初始化其基类型,或委托另一个构造函数间接做到这一点。注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数

    class MyView : View{
        constructor(ctx: Context) : super(ctx)
        constructor(ctx: Context,attrs: AttributeSet):super(ctx,attrs)
    }
    

    在Kotlin中,open标注与Java中的final相反,它标注的类才允许被其他类继承。默认情况下,在Kotlin中所有的类都是final的,这正对应了Effective Java中的要么为继承而设计,并提供文档说明,要么禁止继承。

    覆盖方法

    在Kotlin中力求清晰显式。与Java不同,Kotlin中需要显式标注可以被覆盖的成员(或称开放的成员)和覆盖后的成员:

    open class Base {
        open fun v(){} //可以被复写的成员用open标注
        fun nv(){}
    }
    class Derived() : Base(){
       final override fun v(){} //复写后的成员用override标注,默认override标注的成员也是开放的,如果想再次限制其被覆盖可以显式的用final标注
    }
    

    覆盖属性

    属性覆盖和方法覆盖类似;在子类中声明超类中的同名属性就是覆盖超类中的属性,并且必须以override开头作为标注,并且它们的类型必须兼容。每个声明的属性可以由具有初始化器的属性或者具有getter方法的属性覆盖。

    open class Foo{
        open val x: Int?= null
            get(){//重写get方法
                field = 100
                return field
            }
    }
    class Bar1 : Foo(){
        override val x: Int? = null
    }
    

    在Kotlin中,属性都有默认的getset方法,并且可以被重写,如上面的例子。如果子类中覆盖了父类中的属性,那么在父类中重写的被覆盖属性的get方法,在子类中是无效的。

    val可以被var覆盖
    但是var不能被val覆盖

    覆盖规则

    如果一个类从它的直接超类继承相同成员的多个实现,那么这个类必须必须覆盖这个成员并提供自己的实现(或者用继承来的其中之一)。为了表示采用从哪个超类中继承的实现,我们使用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() 
        }
    }
    

    C同时继承了两个不同f()实现,所以必须在C中覆盖f()并且提供自己的实现来消除歧义。

    抽象类

    类和其中某些成员可以声明为abstract的。抽象成员在本类中可以不实现。抽象类默认是开放的,不需要用open关键字标注。并且我们可以用一个抽象成员覆盖一个非抽象的开放成员

    open class Base{
        open fun f(){}
    }
    abstract class Derived : Base(){
        override abstract fun f()
    }
    

    伴生对象

    在Kotlin中没有静态方法。在大多数情况下,它建议采用包级函数。
    如果你需要写一个无需类的实例来调用,但需要访问类内部的的函数,你可以把它写成该类内对象声明中的一员。

    相关文章

      网友评论

        本文标题:类和对象

        本文链接:https://www.haomeiwen.com/subject/ydovfxtx.html