Kotlin

Kotlin类与继承

类定义 类声明由类名、类首部(指定类型参数,主构造器等)、类正文(用花括号包围)。类首部和正文都是可选的。因此最简单的类定义为: class Empty // Implicitly inherits from Any 类似所有Java类都继承类Object,所有Kotlin类都继承类Any,但Any不是与特定平台(例如JVM)相关的,它不是一个java.lang.Object,这表明当Kotlin与Java代码进行互操作时,为了使用Object的成员方法,Kotlin提供了扩展函数。 例如为了调用Object的wait()/notify()方法,可以将一个kotlin对象foo转型为Object: (foo as java.lang.Object).wait() 为了获取一个kotlin对象的Java类,Kotlin1.1之后可以使用class引用的java扩展属性,也可以直接使用扩展属性javaClass: val fooClass = foo::class.java // class reference val fooClass = foo.javaClass // extension property: javaClass 与Java代码进行互操作,Kotlin在语言层面上是这样设计的,但在编译为Java字节码以及JVM运行时中,每个类总是默认继承了Object。 构造器 Kotlin的构造器分为主构造器(primary constructor)和次要构造器(secondary constructors)。两者都是可选的,即可以不用明确定义任何构造器,这时如果该类不是抽象类,就采用默认生成的无参主构造器。主构造器只能有一个,次要构造器可以有多个,次要构造器必须代理到主构造器,可以是直接的代理或使用其它次要构造器间接代理。造器的可见性默认是public的。 这里讨论下主构造器,先了解下Java对象的初始化,大致说了Java对象初始化机制有三种:实例初始化器(初始化块)、实例变量初始化器、构造器。初始化块和实例变量初始化器可以认为是实例初始化器的两种不同形式,实例变量初始化器只不过定义了实例变量并使用表达式而非块进行了初始化。在对象初始化时,由于存在继承层次结构,每一层级类都需要进行初始化,一个对象从自身开始向上到父类,到父类的父类等等,直到Object类,完成整个类层次的初始化。所以该对象的构造器必须直接或间接地调用父类构造器,这也说明了为什么构造器不属于Java类成员,它不会被子类继承,不然会造成初始化的死循环。构造器是初始化的入口,但不是初始化的全部,并且为了保证初始化过程的顺序,编译器会为每个构造器生成一个<init>方法,包含以下代码: 对另一个构造函数的调用(为了直接或间接调用父类构造器) 初始化器(包括变量初始器器和块初始化器,为了保证初始化器仅运行一次,如果第1步调用是本地另一个构造函数,那么便不需要 初始化器的代码) 构造函数正文 在Kotlin中,初始化块使用init关键字声明: init { print("This is a intializer block.") } 如果一个Kotlin类未继承其它另外定义的类,那么它默认继承类Any, 如下所示: 未定义主构造器 未定义次要构造器:编译器会为其生成一个无参主构造器 定义了次要构造器:那么它将仅有次要构造器,不会自动生成无参构造器 class Car { // ... constructor(type: String, name: String) { // ... } } 定义了主构造器,并且定义了次要构造器 class Car(type: String, name: String) { // ....

October 29, 2017 · 3 min · 434 words · LEOY

Kotlin函数

参考: 函数 函数(Function) Kotlin使用名称函数(function)而非方法(method),我想是为了与Java方法作出区分,和C语言类似函数可以单独定 义和使用,不依赖于类与对象,而Java中的方法只存在于某个类中。由于Kotlin与Java是兼容的,因此在类中定义的函数仍然 适用于方法这个语义。 Kotlin使用fun来声明函数: fun double(x: Int): Int { return 2*x } 参数 函数参数使用Pascal的表示来定义,即name: type。 默认参数值 函数参数可以有默认值,这样在调用函数时如果没有传入某个参数,那么便使用改参数对应的默认值,这样可以从某种程度上减少 方法重载(overload)。在参数类型后,使用=后跟上一个值来定义默认值。 fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { ... } 对于类中方法的重写(override),子类方法总是使用与父类方法相同的默认值,并且子类方法签名中不能有默认值。 open class A { open fun foo(i: Int = 10) { ... } } class B : A() { override fun foo(i: Int) { ... } // no default value allowed } 命名参数值 看到这里,发现这和Python语法太TM像了。默认参数传递是根据位置来判断的,称为位置参数,由于有了默认参数,可能调用时 传入的参数比签名中的少,例如调用时,一个参数值前面有一个忽略了的默认参数,该参数值的位置被提前了,这时根据位置就无 法判断参数值与参数的对应关系,此时需要将该非默认参数值使用参数名明确标出。...

October 29, 2017 · 2 min · 231 words · LEOY