为了账号安全,请及时绑定邮箱和手机立即绑定

Kotlin学习之属性

标签:
Android

Kotlin学习之属性

@(Kotlin学习)

Kotlin中的属性主要有以下几点:

  • Kotlin中允许包级属性的存在,即属性不一定在类里;

  • 所有非抽象属性都强制要求初始化,没有初始化的属性无法通过编译;

  • 标准化的getter和setter;

  • 大量的高级属性修饰符。

一、声明属性

Kotlin的类可以有属性。属性可以用关键字var声明为可变的,也可以是使用val声明为只读的。语法格式如下:

[修饰符]  val|var  属性名[: 属性类型]  [= 初始化语句]
[get() = getter  语句]
[set() = setter  语句]
  • 属性不能缺少初始化语句,要么写在定义属性的地方,要么写在init语句里,否则就会编译错误;

  • 标记为val的属性不能有自定义的setter,因为Kotlin强烈要求属性初始化,标记为val的属性已经在创建对象的时候初始化了,不能再次赋值。

如下例:

class Person(val name: String){
    val age:Int
    val id:Long=0
    val nationality:String
    
    init{
        age=0
    }
}
  • name属性在主构造方法里定义,使用传入的参数进行初始化;

  • age属性在init语句中进行初始化;

  • id属性在定义时进行初始化;

  • nationality属性不是抽象属性,没有在定义时初始化,也没有在init语句中初始化,所以编译错误。

二、Getters与Setters

Kotlin把Java中没有固定标准的getter和setter方法标准化,并规定调用Kotlin类的属性时强制使用setter和getter方法,不会直接操作累的属性。

可以比较一下Kotlin和Java访问属性的写法的差异:

//Kotlin访问属性val  p  = Person("Alex")
println(p.name)
p.name="Bob"
//Java访问属性Person p = new Person("Alex");
System.out.println(p.getName());
p.setName("Bob");

Kotlin中的"对象.属性"会视情况自动编译为调用getter或setter方法。

一个只读属性的语法和一个可变的属性的语法有两方面的不同:

  1. 只读属性的用val开始代替var;

  2. 只读属性不允许setter。

Kotlin中允许属性添加自定义的getter和setter:

class Person(name: String){
    var name=name    set(value){
        field=if (value.isEmpty()) ""else value[0].toUpperCase()+value.substring(1)
    }

    val isValidName
    get() = !name.isEmpty()
}

上面的代码要注意以下几点:

  1. 需要自定义setter或getter的属性,不能放在类头里定义,必须在类体内定义;

  2. getter是一个没有参数、返回类型与属性类型相同的函数。完整的写法应该如下:

get() : 属性类型{
    ....
}
  1. 不能在getter里再调用本属性,因为Kotlin代码里所有对属性的访问都会被编译为getter方法,这样写就会出现无限迭代和StackOverFlowError;

  2. setter的参数列表一般有一个与属性类型相同的参数,没有返回值;

  3. Kotlin中一般用value表示这个参数,当然也可以用其他关键字;

  4. field是表示幕后字段的关键字,在使用时相当于this.name,但是只能在setter方法内。

三、类外属性

在Kotlin类外定义的属性有两种,一是直接写在类外并初始化的包级属性,二是使用constval定义的编译期常量

  1. 在类外定义的包级属性,会被编译为一个“文件类”的静态变量;

  2. 编译器常量使用constval定义在类外,它与包级属性有一定的相似之处。

编译器常量就是Java中常用的常量。Kotlin的编译器常量有一下几点限制:

  • 只能定义类外或对象内;

  • 只能使用String或原生类型初始化;

  • 不能自定义getter。

  • Kotlin中,使用在注解参数中的属性,只能是编译期常量(其他形式的属性不能使用在注解的参数里)

四、延迟初始化属性

一般地,属性声明为非空类型必须在构造函数中初始化。Kotlin强制要求类内定义的非抽象属性都要初始化,但是有些属性不需要在新建实例时初始化,或可能需要外部注入来初始化,这些时候我们都无法按照Kotlin的要求初始化属性。

为了避免编译错误,可以使用lateinit关键字修饰属性。

fun main(args: Array<String>) {
    val person = Person("HXL")
    person.initHello()
    print(person.hello)
}class Person(val name: String){
    lateinit var hello:String
    fun initHello(){
        hello="Hello,my name is $name"
    }
}

使用lateinit关键字修饰hello属性,定义了initHello()函数来初始化hello属性。

如果调用了未初始化的lateinit属性,就会抛出UninitalizedPropertyAccessException。

fun main(args: Array<String>) {
    val person = Person("HXL")    print(person.hello)
}
//上述代码所抛异常Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property hello has not been initialized
    at Person.getHello(app.kt:7)
    at AppKt.main(app.kt:3)

原文链接:http://www.apkbus.com/blog-815579-77281.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消