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方法。
一个只读属性的语法和一个可变的属性的语法有两方面的不同:
只读属性的用val开始代替var;
只读属性不允许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() }
上面的代码要注意以下几点:
需要自定义setter或getter的属性,不能放在类头里定义,必须在类体内定义;
getter是一个没有参数、返回类型与属性类型相同的函数。完整的写法应该如下:
get() : 属性类型{ .... }
不能在getter里再调用本属性,因为Kotlin代码里所有对属性的访问都会被编译为getter方法,这样写就会出现无限迭代和StackOverFlowError;
setter的参数列表一般有一个与属性类型相同的参数,没有返回值;
Kotlin中一般用value表示这个参数,当然也可以用其他关键字;
field是表示幕后字段的关键字,在使用时相当于this.name,但是只能在setter方法内。
三、类外属性
在Kotlin类外定义的属性有两种,一是直接写在类外并初始化的包级属性,二是使用constval定义的编译期常量。
在类外定义的包级属性,会被编译为一个“文件类”的静态变量;
编译器常量使用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)
共同学习,写下你的评论
评论加载中...
作者其他优质文章