Kotlin学习(三): 属性和字段

作者: 叫我旺仔 | 来源:发表于2017-02-28 21:46 被阅读1887次
    Kotlin

    本文是关于Kotlin的属性和字段相关,涉及到有变量、常量还有延迟加载属性。

    声明属性(Declaring Properties)

    Kotlin中可以使用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 = ...
    }
    

    调用的时候与Java一样,通过变量名直接使用一个属性

    fun copyAddress(address: Address): Address {
        val result = Address() // Kotlin不需要使用new关键字
        result.name = address.name
        result.street = address.street
        // ...
        return result
    }
    

    Getter和Setter(Getters and Setters)

    声明属性的完整语法如下,语法中的初始化语句,gettersetter都是可选的

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

    如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型,val不允许设置setter函数,以为它是只读的。

    var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
    var initialized = 1 // 类型为 Int, 默认实现了 getter 和 setter
    val simple: Int? // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
    val inferredType = 1 // 类型为 Int 类型,默认实现 getter
    

    可以自定义访问器(getter)和自定义settersetter的参数名默认是value,也可以自定义

    val isEmpty: Boolean
        get() = this.size == 0
    
    var stringRepresentation: String
        get() = this.toString()
        set (value) {
            setDataFormString(value) // 格式化字符串,并且将值重新赋值给其他元素
        }
    

    如果需要设置访问器的可见性或者设置注解,又不改变原来的实现,则可以设置一个不带函数的访问器

    var setterVisibility: String = "abc" // 非空类型必须初始化
        private set // setter是私有的并且有默认的实现
    
    var setterWithAnnotation: Any? = null // 设置为可空
        @Inject set // 用 Inject 注解 setter
    

    备用字段(Backing Fields)

    Kotlin中的类并不允许使用字段,在自定义gettersetter的时候,可以使用field来起到局部变量的作用。

    var counter = 0 //初始化值会直接写入备用字段
        get() = field
        set(value) {
            if (value >= 0)
                field  = value
        }
    

    编译器会检查访问器的代码,如果使用了备用字段(或者访问器是默认的实现逻辑),就会自动生成备用字段,否则就不会。

    // 这种情况并不需要备用字段,所有不会生成备用字段
    val isEmpty: Boolean
        get() = this.size == 0
    

    注意:field标识符只允许在属性的访问器函数内使用.

    备用属性(Backing Properties)

    备用属性,可以看作是备用变量(Backing Fields)的变种,其实际上也是隐含试的对属性值的初始化声明,避免了空指针。

    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")
        }
    

    不管是备用变量或者备用属性,都是Kotlin对于空指针的一种解决方案,可以避免函数访问私有属性而破坏它的结构。

    编译时常量(Compile-Time Constants)

    那些在编译时就能知道具体值的属性可以使用const修饰符标记为编译时常量. 这种属性需要同时满足以下条件:

    • 顶层或对象的成员(Top-level or member of an object)
    • 以String或基本类型进行初始化
    • 没有自定义getter

    这种属性可以当作注解使用

    const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
    @Deprected(SUBSYSTEM_DEPRECATED) fun foo() { ... }
    

    Top-level(顶级)

    Top-level属性或者方法,与class同级,如下面所示,类名是Kot

    package foo.bar
    
    val prop: String = "top-level-prop"
    fun demo() {
        loge("top-level", "top-level-demo()")
    }
    
    class Kot {
        fun v() {
            loge("top-level", prop)
            demo()
        }
    }
    

    在编译成class的时候,会把Top-level的属性和函数创建到以类名+Kt为名的class文件中

    KotKt.class

    Top-level调用的时候类似于调用扩展函数那样,直接调用属性或者函数。

    loge("top-level", prop)
    demo()
    
    log

    延迟初始化属性(Late-Initialized Properties)

    在Kotlin中,声明为具有非空类型的属性必须在构造函数中初始化,但是往往不希望在构造函数中初始化,例如在通过依赖注入或单元测试的设置方法来初始化属性的时候,不能在构造器中提供一个非空的初始化语句,为了处理这种情况,就要在属性上加lateinit关键字来延迟初始化

    public class MyTest {
        lateinit var subject: TestSubject
    
        @SetUp fun setup() {
            subject = TestSubject()
        }
    
        @Test fun test() {
            subject.method() 
        }
    }
    

    lateinit只能够在var类型的属性中,不能用于构造函数,而且属性不能有自定义的gettersetting,这些属性必须是非空类型,并且不能是基本类型。

    如果在一个延迟初始化的属性初始化前调用,会导致一个特定异常,调用的时候值还没有初始化.

    相关文章

      网友评论

      • f49fc94b027b:Top-level不太懂
      • jblz625:这一章 我个人觉得比较难理解.很空洞,这一块和java有比较大的差异,如果以对比的方式来解释会不会更好一点,例如java 的构造函数 用Kotlin怎么实现类似功能
        叫我旺仔:嗯,我会找时间修改下,感想提醒。:smile:
      • 程自舟:现在还不敢正式用
        26257f20415d:@叫我旺仔 了解了解先 现在短时间是替换不了java的 公司项目还需要谨慎使用 学习一下还是不错的
        叫我旺仔:@程自舟 如果项目还没完善,那就不要正式用。

      本文标题:Kotlin学习(三): 属性和字段

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