Kotlin学习笔记——属性和字段

时间:2023-02-06 15:43:27

声明属性

在类里面使用var或者val就可以声明了。

public class Address { 
public var name: String = ...
public var street: String = ...
public var city: String = ...
public var state: String? = ...
public var zip: String = ...
}

只需要将成员变量定义成一个变量,默认是 public 的。编译器会自动生成 getter 和 setter 方法。所以上面的属性编译器默认添加了getter 和 setter 方法。

属性的使用

fun copyAddress(address: Address): Address {
val result = Address() // there's no 'new' keyword in Kotlin
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}

上面对属性的访问,并不是像Java里面一样,直接访问属性的本身,而是默认调用了getter 和 setter 方法。

Getters and Setters

完整的属性声明如下:

var <propertyName>: <PropertyType> [= <property_initializer>]
[<getter>]
[<setter>]

其中initializer, getter 和 setter都是可选的。var是允许有getter 和 setter方法,如果变量是val声明的,它类似于Java中的final,所以如果以val声明就不允许有setter方法。

val isEmpty: Boolean
get() = this.size == 0

var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // parses the string and assigns values to other properties
}

下面举个例子:

class Person {
var name: String = "abc"
get() = field.toUpperCase()
set(value){
field = "Name: $value"
}
}

fun main(args: Array<String>) {
var customer: Person = Person()
println(customer.name) // ABC
customer.name = "aaa"
println(customer.name) //NAME: AAA
}

对于属性,如果你想改变访问的可见性或者是对其进行注解,但是又不想改变它的默认实现,那么你就可以定义set和get但不进行实现。

var setterVisibility: String = "abc" // Initializer required, not a nullable type
private set // the setter is private and has the default implementation

var setterWithAnnotation: Any?
@Inject set // annotate the setter with Inject

Backing Fields

在上面例子中定义的Person类里面,属性的get和set方法里面使用了一个field,它是一个自动的返回字段,代表的就是属性。

var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0)
field = value
}

field只有在访问的时候才会产生,其他时候是不会产生的。

Backing Properties

如果Backing Fields不适用的话,其实可以直接使用返回属性就可以了。

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null)
_table = HashMap() // Type parameters are inferred
return _table ?: throw AssertionError("Set to null by another thread")
}

延迟初始化属性

对于非空类型的属性是必须初始化的。如果我们希望延迟进行初始化,就可以使用lateinit关键字了。

public class MyTest {
lateinit var subject: TestSubject

@SetUp fun setup() {
subject = TestSubject()
}

@Test fun test() {
subject.method() // dereference directly
}
}

参考文章:Properties and Fields