类与对象
####基本构造
//使用class声明,默认为public
class Invoice{
}
//如果没有类体,可以忽略花括号
class Empty
//构造函数若没有任何注解或修饰符,则可以省略constructor关键字
class Person constructor(firstName : String){}
//若类需要初始化,需要放入init块中,不能放入构造函数中(阿里开发文档亦有此规范)
class Customer(name : String){
init{
logger.info("Customer initialized with value ${name}")
}
}
//构造方法的参数可以在初始快中使用,也可以在类体内声明的属性初始化器中使用
class Customer(name : String ){
val customerKey = name.toUpperCase()
}
//次构造函数
class Person{
consructor(parent : Person){
parent.children.add(this)
}
}
//若没有声明任何构造函数,则会生成一个不带参数的主构造函数,默认为public。若主构造函数的所有参数都由默认值,也会生成一个默认的无参构造函数
class DontCreateMe private constructor(){}
//Kotlin中没有new关键字,创建类的实例。类似于调用方法
val invoice = Invoice()
继承与覆盖规则
Kotlin中所有类都继承于_Any_,类似于Java中的Object。若没有显式继承某个类,则默认继承自_Any_。语法如下:
//使用open 显式标记该类为用于继承的父类,Kotlin中所有类默认都为final
open class Base(p:Int)
class Drived(p:Int) : Base(p)
/**如果该类有一个主构造函数,其基类型可以(并且必须) 用(基类型 的)主构造函数参数就地初始化。
如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数*/
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
//成员若可以被覆盖,也需要标记为open,否则默认为final,重写方法必须显式使用override,若需要避免再次被覆盖,可以使用final
open class Base{
open fun v() {}
fun nv(){}
}
class Derived() : Base() {
override fun v(){}
}
//属性同样可以被覆盖,但是规则如上。需要补充的是,var可以覆盖val,但反之则不行
//调用父类方法或构造,需要使用super关键字
//若需要在一个内部类访问外部类的父类,需要使用外部类名限定的super关键字来实现
class Bar : Foo(){
override fun f() {}
override val x : Int get() = 0
inner class Baz{
fun g(){
super@Bar.f()
println(super@Bar.x)
}
}
}
/**覆盖规则:
如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base>:*/
open class A{
open fun f() { println("A")}
fun a () { println("a") }
}
interface B{
fun f() {println("B")}
fun b() {println("b")}
}
class C():A(),B(){
override fun f(){
super<A>.f()
super<B>.f()
}
}
//Kotlin也有抽象类,但是抽象类不需要使用open来表示
open class Base{
open fun f() {}
}
abstract class Derived : Base(){
override abstract fun f()
}
//伴生对象,类似于Java的静态方法,调用方式一直,本质不同
class MyClass{
companion object Factory{
fun create() : Myclass = MyClass()
}
}
val instance = MyClass.create()
属性
属性的声明,可用val和var
class Address{
var name : String = ...
var street : String = ...
var city : String = ...
var state : String? = ...
var zip : String = ...
}
调用方式,Kotlin中没有new,类似于Java中public变量的访问方式
fun copyAddress(address : Address):Address{
val result = Address()
result.name = address.name
...
return result
}
Getters与Setters语法
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
若属性类型可以从初始器推导出来,也可以省略
var allByDefault : Int? // 错误,这里需要显式初始化器
var initialized = 1 //默认推导为Int
自定义getter和settter
var stringRepersentation:String
get() = this.toString()
set(value){
setDataFromString(value)
}
每个属性的访问器都由一个幕后字段,使用field来表示
var counter = 0
set (value){
if(value >= 0){
field = value
}
}
幕后属性
private var _table:Map<String , Int>? = null
public val table: Map<String , Int>
get(){
if(_table == null){
_table = HashMap()
}
return _table ?: throw AssertionError("Set to null by another thread")
}
编译期常量,使用_const_修饰,类似于Java的static常量,但是Kotlin和Java的常量不能互相直接调用,若在Java中需要调用Kotlin的常量,需要加@JvmStatis的注解,例如:
const val SUBSYSTEM_DEPRECATED : String = "This subsystem is deprecated"
//可用于注解中
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo(){...}
延迟初始化属性
一般用于依赖注入这种情况,避免初始化前进行访问
public class MyTest{
lateinit var subject : TestSubject
@SetUp fun setup(){
subject = TestSubject()
}
@Test fun test(){
subject.method()
}
}