java中属性的可见性_属性及可见性

分类

类中的属性有两种:

可以存储值的属性

不存储属性值,每一次访问都需要通过 getter / setter 方法,因此每一次访问都需要计算。

interface Parent {

val name: String

val age: Int

get() {

println("getter")

return 10

}

}

class Child:Parent{

override val name = "name" // 可以存储值。也可以通过 getter / setter 获取修改

set(value) {

println("setter ${field} ${value}")

field = value

}

}

getter 与 setter

在方法内部,使用特殊标识符 field 访问支持字段的值。

class Child {

var i = 0

var name = "name"

set(value) {

println("setter ${field} ${value}")

field = value // 为字段赋值

}

get() {

println("get ${field}")

i++

field = "${i}"

return "${i}"

}

}

fun main(args: Array) {

val c = Child()

println(c.name)

c.name = "main--"

println(c.name)

}

其输出结果为:

70199809c39f?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

输出结果

可以修改 getter/setter 的可见性。

class Test {

var name = ""

private set(value) { // 将 setter 可见性设置为 private

field = value

}

}

可见性

默认的修饰符是 public

kt 新增修饰符 internal:模板可见。一个模板指的是一起编译的 kt 文件。

protected 只能用于修饰类中的成员

可见性低的类不能用于可见性高的类、方法、属性。

与 java 一样,重写可以提升可见性,但不能降低可见性。

internal class User()

open class Person()

class Student:Person(){

internal var user:User = User()

internal fun test():User = User()

}

上述代码中,由于 User 定义为 internal,所以 Student 类的 user 属性、test() 方法都只能定义成比 internal 或比它低的可见性。

同理,如果将 Person 类的可见性定义 internal ,则 Student 不能继承,除非将 Student 也定义成 internal 或比它低的可见性。

修饰符

类成员

顶层声明

public(默认)

所有地方可见

所有地方可见

internal

模块中可见

模块中可见

protected

子类可见

- (不能修饰)

private

类中可见

文件中可见

属性委托

使用关键字 by ,将属性的访问器委托给另一个实例。

属性委托只有在属性被访问时才进行初始化,与 lazy 函数类似。

格式

属性委托基本语法如下:

class Demo{

var p:Type by Delegate()

}

属性 p 将自己的 getter/setter 逻辑委托给了另一个对象,这里是 Delegate 的一个实例:通过对 by 后的表达式求值来获取这个实例。上述代码等价如下代码:

class Demo {

private val delegate = Delegate()

var p: Type

get() = delegate.getValue()

set(value) = delegate.setValue(value)

}

惰性初始化

lazy 函数会延迟加载,再结构 by 关键字可以实现委托属性。

在代码中,经常需要使用 惰性初始化:只有当需要该属性的时候才对属性进行初始化。

如下类,初始化时,并没有初始化 s,只有当访问 s 时才进行初始化,并且将初始化的值存储于 _s 中,这样下次访问时可以直接返回,这就是所谓的惰性初始化:

class Test {

private var _s: String? = null

val s: String

get() {

if (_s == null)

_s = "sss"

return _s!!

}

}

上述代码有点啰嗦,如果有多个惰性属性,这些模板代码需要写多次。而 属性委托可以让代码变得简单,可以封装用于存储值的支持属性以及确保该值只会被初始化一次。

委托类的构造

委托类有如下要求:

定义 getValue 与 setValue(如果是 val 变量,不需要)方法,且被声明为 operator

方法至少有两个参数,一个用于接收属性的实例;一个用于表示属性本身,其类型为 KProperty。可以通过 KProperty.name 获取属性名。

结合关键字 by ,kt 编译器自动完成 ‘惰性初始化‘ 中代码的功能

fun main(args: Array) {

val d = Demo()

println(d.a) // 会输出 getValue ,然后再输出 1

d.a = 3 // 会输出 setValue

println(d.a) // 会输出 getValue ,然后再输出 3

}

class TestDelegate(var propValue: Int) {

operator fun getValue(demo: Demo, name: KProperty): Int {

println("getValue")

return propValue

}

operator fun setValue(demo: Demo, name: KProperty, newValue: Int) {

println("setValue")

propValue = newValue

}

}

class Demo {

var a: Int by TestDelegate(1)

}

从输出中可以发现:访问 a 属性时,所有的请求都转发到 TestDelegate 对应的方法中。这就是所谓的属性委托。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值