Kotlin学习笔记——类和对象

来源:互联网 发布:php参考手册 编辑:程序博客网 时间:2024/05/20 06:54

跟Java一样,Kotlin里面类的声明使用的是关键字class,类的声明包含有三部分:类名,类头,类体,其中,类头和类体是可选的。

class Empty
  • 1
  • 1

Constructors

在Kotlin中,一个类有一个primary constructor,一个或多个secondary constructors。primary constructor 属于类头部分,它在类名之后。

class Person constructor(firstName: String) {}
  • 1
  • 2
  • 1
  • 2

如果primary constructor没有任何注解或者指示符,constructor关键字可以被省略。

class Person(firstName: String) {}
  • 1
  • 2
  • 1
  • 2

相反,如果primary constructory有注解或者可见的指示符,constructor是必须的。

class Customer public @Inject constructor(name: String) { ... }
  • 1
  • 1

primary constructor不能包含任何的代码,初始代码可以放在初始块中,初始化代码块以init关键字开头。

class Customer(name: String) {    init {        logger.info("Customer initialized with value ${name}")    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

需要注意的是,在主构造函数里,可以直接用这些参数变量赋值给类的属性,或者用构造代码块来实现初始化。

class Customer(firstName: String, lastName: String, email: String) {  var firstName: String  var lastName: String  var email: String  init {    this.firstName = firstName    this.lastName = lastName    this.email = email  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

也可以直接把primary constructor中的参数直接声明成为类的属性,定义的方法是在参数名前加上 var 或者 val 关键字,val 是代表属性是常量。在创建类的时候,调用构造函数就直接把它们进行了初始化,这样就不用在类中单独声明类的属性了。

class Customer(  var firstName: String,  var lastName: String,  var email: String)
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Secondary Constructors

除了primary constructory,还有secondary constructors,同样也是constructor开头,位于类体中。 
值得说明的是,如果primary constructory和secondary constructors同时存在,每个secondary constructor需要委托到primary constructor中去,或者间接通过另一个secondary constructors来委托。使用方法就是使用this,表示委托到本类的另一个构造函数中。

class Person(val name: String) {    constructor(name: String, parent: Person) : this(name) {        parent.children.add(this)    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

如果非抽象的类没有声明任何的构造函数,它默认继承一个没有任何参数的公有构造器,这个跟Java中的默认构造器类似。如果希望它继承的是一个私有的构造器,就需要显示的指明。

class DontCreateMe private constructor () {}
  • 1
  • 2
  • 1
  • 2

创建类实例

跟Java类似,只是没有new关键字。

val invoice = Invoice()val customer = Customer("Joe Smith")
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

类成员

1、构造器和初始化块 
2、成员函数 
3、属性 
4、内部类 
5、对象声明

继承

在Kotlin中所以的类都有一个默认的父类Any,这个类似于Java中的Object。

class Example // Implicitly inherits from Any
  • 1
  • 1

显示的定义一个父类

open class Base(p: Int)class Derived(p: Int) : Base(p)
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

open关键字跟Java中的final是恰恰相反的。

从上面看到,如果父类有primary constructor,子类必须在继承的时候以primary constructor的形式继承。

如果父类没有primary constructor,子类的每个secondary constructor在右边使用super来对它进行初始化。

class MyView : View {    constructor(ctx: Context) : super(ctx) {    }    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

重写成员函数

对于可以重写的函数,都需要显示的指明,使用的是open关键字。如果没有,在子类中声明跟父类相同的方法是非法的。

open class Base {  open fun v() {}  fun nv() {}}class Derived() : Base() {  override fun v() {}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在子类中,如果是重新父类的函数也需要使用override关键字显示的指明。

在子类中被标记为override的成员函数本身也是可以被重新的,也就是open的,如果希望它禁止被重写,需要使用final关键字。

open class AnotherDerived() : Base() {  final override fun v() {}}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

重写规则

如果一个类继承自多个类,并且它的这些父类都有同一个可以重写的函数,那么这个类必须重写这个函数并且提供它自己的实现,另外在子类中指示父类的方法是super<A>,A为父类类名,这样就可以指示不同的父类了。

open class A {  open fun f() { print("A") }  fun a() { print("a") }}interface B {  fun f() { print("B") } // interface members are 'open' by default  fun b() { print("b") }}class C() : A(), B {  // The compiler requires f() to be overridden:  override fun f() {    super<A>.f() // call to A.f()    super<B>.f() // call to B.f()  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

上面类A和B都有f()函数可以重写,所以C类,必须重写这个函数f(),主要是为了消除歧义。

抽象类

跟Java一样,使用abstract关键字。

open class Base {  open fun f() {}}abstract class Derived : Base() {  override abstract fun f()}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Companion Objects

Kotlin 移除了 static 的概念。通常用 companion object 来实现类似功能。

你可能时常会看到一个 Activity 有一个 静态类型的 string,名叫TAG,和一个启动 Activity 的静态方法。Java 中的实现如下:

class LaunchActivity extends AppCompatActivity {  public static final String TAG = LaunchActivity.class.getName();  public static void start(Context context) {    context.startActivity(new Intent(context, LaunchActivity.class));  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在 Kotlin 下的实现如下:

class LaunchActivity {  companion object {    val TAG: String = LaunchActivity::class.simpleName    fun start(context: Context) {      context.startActivity(Intent(context, LaunchActivity::class))    }  }}Timber.v("Starting activity ${LaunchActivity.TAG}")LaunchActivity.start(context)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Sealed Classe

它类似于一个扩展的enum类,不同的是枚举的实例是唯一的,而密封类可以有很多实例,它们可以有不同的状态。它使用的关键字是sealed。

sealed class Expr {    class Const(val number: Double) : Expr()    class Sum(val e1: Expr, val e2: Expr) : Expr()    object NotANumber : Expr()}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们可以使用when表达式匹配所有选项而不使用else分支:

fun eval(expr: Expr): Double = when(expr) {    is Const -> expr.number    is Sum -> eval(expr.e1) + eval(expr.e2)    NotANumber -> Double.NaN    // the `else` clause is not required because we've covered all the cases}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

参考文章:Classes and Inheritance

原创粉丝点击