Appearance
Kotlin 委托属性详解 🔧
Android 面试必考 Kotlin 委托属性,包含 by 关键字、标准委托、自定义委托、委托属性原理等核心知识点
目录
- by 关键字
- [标准委托(lazy、observable、vetoable、map)](#2-标准委托 lazyobservablevetoablemap)
- 自定义委托
- 委托属性原理
- ReadWriteProperty/ReadOnlyProperty
- 面试考点汇总
1. by 关键字
1.1 基础语法
委托属性允许将属性的 getter/setter 委托给另一个对象处理:
kotlin
// 基本语法:val/var 属性名:类型 by 委托对象
class Example {
var property: String by Delegate()
}
// 委托类需要实现 getValue 和 setValue
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "value"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
// 处理赋值
}
}1.2 委托属性的使用
kotlin
// 委托类
class Delegate {
private var value: String = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("Getting ${property.name}")
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("Setting ${property.name} to $value")
this.value = value
}
}
// 使用委托属性
class Example {
var property: String by Delegate()
}
// 使用
val example = Example()
example.property = "Hello" // 调用 setValue
println(example.property) // 调用 getValue1.3 委托的要求
kotlin
// 对于 var 属性,委托需要 getValue 和 setValue
class VarDelegate<T> {
private var value: T? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value as T
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
// 对于 val 属性,只需要 getValue
class ValDelegate<T>(private val initialValue: T) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return initialValue
}
}
// 使用
class Example {
var varProp: String by VarDelegate()
val valProp: String by ValDelegate("initial")
}1.4 委托属性的实际场景
kotlin
// 1. 懒加载
class Config {
val data: String by lazy {
println("Loading config...")
loadConfigFromFile()
}
}
// 2. 可观察属性
class User {
var name: String by Delegates.observable("<no name>") {
property, old, new ->
println("$property changed from $old to $new")
}
}
// 3. 非空属性
class Presenter {
lateinit var view: View
// 或
var view: View? by NotNullVar()
}
// 4. Map 委托
class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}2. 标准委托(lazy、observable、vetoable、map)
2.1 lazy 委托
kotlin
// 基础用法
class Example {
val value: String by lazy {
println("Computing...")
"Hello"
}
}
// 使用
val example = Example()
println(example.value) // 第一次:打印 "Computing..." 然后 "Hello"
println(example.value) // 第二次:只打印 "Hello"
// lazy 的三种模式
val lazy1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { compute() }
// 默认,线程安全,使用锁保证只计算一次
val lazy2 by lazy(LazyThreadSafetyMode.PUBLICATION) { compute() }
// 多线程初始化,可能多次计算,但返回相同结果
val lazy3 by lazy(LazyThreadSafetyMode.NONE) { compute() }
// 单线程,最快,无锁
// 实际场景
class Repository {
private val database: Database by lazy {
Database.connect()
}
private val api: ApiService by lazy {
Retrofit.Builder().build()
}
}2.2 lazy 的实现原理
kotlin
// lazy 返回 Lazy<T> 接口
public interface Lazy<out T> {
public val value: T
public fun isInitialized(): Boolean
}
// 实现类(简化版)
private class SynchronizedLazyImpl<out T>(
private val initializer: () -> T,
private val lock: Any = this
) : Lazy<T>, Serializable {
@Volatile private var value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
val v = value
if (v !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return v as T
}
return synchronized(lock) {
val v2 = value
if (v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
v2 as T
} else {
val typedValue = initializer()
value = typedValue
typedValue
}
}
}
override fun isInitialized(): Boolean = value !== UNINITIALIZED_VALUE
}
// 使用
val lazyValue: String by lazy { "Hello" }
println(lazyValue) // 初始化
println((lazyValue as Lazy<*>).isInitialized()) // true2.3 observable 委托
kotlin
// 基础用法
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
property, old, new ->
println("$property changed from $old to $new")
}
}
// 使用
val user = User()
user.name = "张三" // 打印:property name changed from <no name> to 张三
user.name = "李四" // 打印:property name changed from 张三 to 李四
// 实际场景:通知 UI 更新
class ViewModel {
var userName: String by Delegates.observable("") { _, _, _ ->
notifyUiChanged()
}
private fun notifyUiChanged() {
// 通知 UI 更新
}
}
// 多个观察者
class ObservableExample {
private val observers = mutableListOf<(String) -> Unit>()
fun addObserver(observer: (String) -> Unit) {
observers.add(observer)
}
var value: String by Delegates.observable("") { _, old, new ->
observers.forEach { it(new) }
}
}2.4 vetoable 委托
kotlin
// 基础用法:可以拒绝更新
import kotlin.properties.Delegates
class User {
var age: Int by Delegates.vetoable(0) { property, old, new ->
if (new < 0) {
println("Age cannot be negative")
false // 拒绝更新
} else if (new > 150) {
println("Age cannot be greater than 150")
false // 拒绝更新
} else {
true // 允许更新
}
}
}
// 使用
val user = User()
user.age = 25 // ✅ 允许
user.age = -1 // ❌ 拒绝,保持原值
user.age = 200 // ❌ 拒绝,保持原值
// 实际场景:状态机
class StateMachine {
var state: State by Delegates.vetoable(State.Initial) { _, old, new ->
when {
old == State.Initial && new == State.Loading -> true
old == State.Loading && new == State.Success -> true
old == State.Loading && new == State.Error -> true
else -> {
println("Invalid state transition: $old -> $new")
false
}
}
}
}
enum class State { Initial, Loading, Success, Error }2.5 map 委托
kotlin
// 基础用法:从 Map 中读取/写入值
class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
// 使用
val user = User(mapOf(
"name" to "张三",
"age" to 25
))
println(user.name) // "张三"
println(user.age) // 25
// 可变 Map 委托
class MutableUser(map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
// 使用
val mutableMap = mutableMapOf<String, Any?>()
val mutableUser = MutableUser(mutableMap)
mutableUser.name = "李四"
mutableUser.age = 30
println(mutableMap) // {name=李四,age=30}
// 实际场景:JSON 解析
class JsonUser(json: Map<String, Any?>) {
val id: Int by json
val name: String by json
val email: String? by json // 可空
}
// 带默认值
class UserWithDefault(map: Map<String, Any?>) {
val name: String by map.withDefault { "Unknown" }
val age: Int by map.withDefault { 0 }
}2.6 其他标准委托
kotlin
// notNull 委托(已废弃,使用 lateinit 或可空类型)
class NotNullExample {
var name: String by Delegates.notNull()
fun init() {
name = "Kotlin"
}
}
// 使用
val example = NotNullExample()
// println(example.name) // ❌ 抛 IllegalStateException
example.init()
println(example.name) // ✅ "Kotlin"
// 推荐替代方案
class BetterExample {
lateinit var name: String
// 或
var name: String? = null
}3. 自定义委托
3.1 基础自定义委托
kotlin
// 实现 ReadWriteProperty 接口
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class NotNullVar<T> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException(
"Property ${property.name} not initialized"
)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
// 使用
class Example {
var name: String by NotNullVar()
}
// 实际使用
val example = Example()
// println(example.name) // ❌ 抛异常
example.name = "Kotlin"
println(example.name) // ✅ "Kotlin"3.2 延迟初始化委托
kotlin
// 自定义延迟初始化
class LateInit<T> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException(
"Property ${property.name} has not been initialized"
)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (this.value != null) {
throw IllegalStateException("Property ${property.name} already initialized")
}
this.value = value
}
val isInitialized: Boolean
get() = value != null
}
// 使用
class Example {
var config: Config by LateInit()
}
// 实际场景:依赖注入
class DIContainer {
private val services = mutableMapOf<String, Any>()
fun <T : Any> register(name: String, service: T) {
services[name] = service
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> get(name: String): T {
return services[name] as? T
?: throw IllegalStateException("Service $name not registered")
}
}
class ServiceDelegate<T : Any>(private val name: String) : ReadWriteProperty<Any?, T> {
private val container = DIContainer()
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return container.get(name)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
container.register(name, value)
}
}
// 使用
class MyService
class AnotherService
class Client {
var service: MyService by ServiceDelegate("myService")
var another: AnotherService by ServiceDelegate("anotherService")
}3.3 observable 自定义实现
kotlin
// 自定义 observable
class ObservableProperty<T>(
private val initialValue: T,
private val onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit
) : ReadWriteProperty<Any?, T> {
private var value = initialValue
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
this.value = value
onChange(property, oldValue, value)
}
}
// 使用
class User {
var name: String by ObservableProperty("<no name>") { prop, old, new ->
println("${prop.name} changed from $old to $new")
}
}
// 多个观察者
class MultiObservableProperty<T>(
private val initialValue: T
) : ReadWriteProperty<Any?, T> {
private val observers = mutableListOf<(T, T) -> Unit>()
private var value = initialValue
fun addObserver(observer: (old: T, new: T) -> Unit) {
observers.add(observer)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
this.value = value
observers.forEach { it(oldValue, value) }
}
}3.4 缓存委托
kotlin
// 缓存委托:首次计算后缓存结果
class CachedProperty<T>(
private val compute: () -> T
) : ReadOnlyProperty<Any?, T> {
private var cached: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return cached ?: compute().also { cached = it }
}
fun invalidate() {
cached = null
}
}
// 使用
class Repository {
val users: List<User> by CachedProperty {
println("Loading users from database...")
loadUsersFromDatabase()
}
}
// 带过期时间的缓存
class TimedCachedProperty<T>(
private val compute: () -> T,
private val ttlMs: Long
) : ReadOnlyProperty<Any?, T> {
private var cached: T? = null
private var expireTime: Long = 0
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val now = System.currentTimeMillis()
if (cached == null || now > expireTime) {
cached = compute()
expireTime = now + ttlMs
}
return cached!!
}
}
// 使用
class ApiService {
val config: Config by TimedCachedProperty(
compute = { fetchConfigFromServer() },
ttlMs = 5 * 60 * 1000 // 5 分钟
)
}3.5 绑定委托
kotlin
// 双向绑定委托
class BindableProperty<T>(
private val initialValue: T,
private val onSet: (T) -> Unit
) : ReadWriteProperty<Any?, T> {
private var value = initialValue
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
onSet(value)
}
}
// 使用:UI 绑定
class ViewModel {
var text: String by BindableProperty("") { newText ->
updateTextView(newText)
}
private fun updateTextView(text: String) {
// 更新 UI
}
}
// 计算属性委托
class ComputedProperty<T, R>(
private val source: ReadWriteProperty<Any?, T>,
private val compute: (T) -> R,
private val reverse: (R) -> T
) : ReadWriteProperty<Any?, R> {
override fun getValue(thisRef: Any?, property: KProperty<*>): R {
return compute(source.getValue(thisRef, property))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: R) {
source.setValue(thisRef, property, reverse(value))
}
}
// 使用
class Temperature {
private var celsius: Double by Delegates.observable(0.0) { _, _, _ ->
println("Temperature changed")
}
var fahrenheit: Double by ComputedProperty(
source = this::celsius,
compute = { c -> c * 9 / 5 + 32 },
reverse = { f -> (f - 32) * 5 / 9 }
)
}4. 委托属性原理
4.1 编译原理
委托属性在编译时被转换为委托对象的调用:
kotlin
// Kotlin 代码
class Example {
var prop: String by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "value"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
// ...
}
}
// 编译后(伪代码)
class Example {
private val delegate = Delegate()
var prop: String
get() = delegate.getValue(this, ::prop)
set(value) = delegate.setValue(this, ::prop, value)
}4.2 KProperty 参数
kotlin
// KProperty 提供属性元数据
import kotlin.reflect.KProperty
class LoggingDelegate<T> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
println("Getting ${property.name}")
return value as T
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
println("Setting ${property.name} to $value")
this.value = value
}
}
// KProperty 的常用属性
// - name: 属性名
// - returnType: 返回类型
// - annotations: 注解
// - isAbstract: 是否抽象
// - isFinal: 是否 final
// - isOpen: 是否 open
// 使用示例
class Example {
var name: String by LoggingDelegate()
}
val example = Example()
example.name = "Kotlin" // 打印:Setting name to Kotlin
println(example.name) // 打印:Getting name4.3 thisRef 参数
kotlin
// thisRef 是属性所属的对象实例
class Delegate : ReadWriteProperty<MyClass, String> {
private var value: String = ""
override fun getValue(thisRef: MyClass, property: KProperty<*>): String {
// thisRef 是 MyClass 实例
println("Getting from ${thisRef::class.simpleName}")
return value
}
override fun setValue(thisRef: MyClass, property: KProperty<*>, value: String) {
this.value = value
}
}
class MyClass {
var prop: String by Delegate()
}
// 使用 Any? 作为 thisRef 类型可以适用于任何类
class GenericDelegate<T> : ReadWriteProperty<Any?, T> {
// ...
}4.4 委托的线程安全
kotlin
// 线程安全的委托
class ThreadSafeDelegate<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value: T = initialValue
private val lock = Any()
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
synchronized(lock) {
return value
}
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
synchronized(lock) {
this.value = value
}
}
}
// 使用 volatile
class VolatileDelegate<T>(@Volatile private var value: T) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
// 使用 AtomicInteger 等原子类
class AtomicDelegate(initialValue: Int) : ReadWriteProperty<Any?, Int> {
private val atomic = AtomicInteger(initialValue)
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return atomic.get()
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
atomic.set(value)
}
}4.5 委托与继承
kotlin
// 委托可以被继承
open class Base {
var name: String by Delegates.observable("") { _, old, new ->
println("Base: $old -> $new")
}
}
class Derived : Base() {
// 继承 name 属性
}
// 使用
val derived = Derived()
derived.name = "Kotlin" // 打印:Base: -> Kotlin
// 重写委托属性
class Derived2 : Base() {
override var name: String = ""
// 不再使用委托
}5. ReadWriteProperty/ReadOnlyProperty
5.1 接口定义
kotlin
// ReadOnlyProperty - 只读属性委托
public interface ReadOnlyProperty<in R, out T> {
public operator fun getValue(thisRef: R, property: KProperty<*>): T
}
// ReadWriteProperty - 可读写属性委托
public interface ReadWriteProperty<in R, T> {
public operator fun getValue(thisRef: R, property: KProperty<*>): T
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}5.2 实现 ReadOnlyProperty
kotlin
// 只读委托示例
class ConstantProperty<T>(private val value: T) : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
}
// 使用
class Example {
val pi: Double by ConstantProperty(3.14159)
val e: Double by ConstantProperty(2.71828)
}
// 计算只读属性
class ComputedReadOnlyProperty<T>(
private val compute: () -> T
) : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return compute()
}
}
// 使用
class MathConstants {
val random: Double by ComputedReadOnlyProperty { Math.random() }
}5.3 实现 ReadWriteProperty
kotlin
// 完整的可读写委托
class FullDelegate<T>(
initialValue: T,
private val onGet: (T) -> Unit = {},
private val onSet: (T) -> Unit = {}
) : ReadWriteProperty<Any?, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
onGet(value)
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
onSet(value)
}
}
// 使用
class Example {
var name: String by FullDelegate(
initialValue = "",
onGet = { println("Getting: $it") },
onSet = { println("Setting: $it") }
)
}5.4 委托提供者(ProvideDelegate)
kotlin
// provideDelegate 在创建委托时调用
class ResourceProvider {
operator fun provideDelegate(
thisRef: MyActivity,
property: KProperty<*>
): ReadOnlyProperty<MyActivity, View> {
// 在创建委托时执行,可以用于查找 View
val view = thisRef.findViewById<View>(getResourceId(property.name))
return Property { _, _ -> view }
}
private fun getResourceId(name: String): Int {
// 根据属性名获取资源 ID
return 0
}
}
class Property(
private val value: View
) : ReadOnlyProperty<MyActivity, View> {
override fun getValue(thisRef: MyActivity, property: KProperty<*>): View {
return value
}
}
// 使用
class MyActivity {
val button: View by ResourceProvider()
// provideDelegate 在初始化时调用
}
// 实际场景:ViewBinding
class ViewBindingDelegate<T : ViewBinding>(
private val factory: (View) -> T
) : ReadOnlyProperty<Activity, T> {
private var binding: T? = null
override fun getValue(thisRef: Activity, property: KProperty<*>): T {
return binding ?: factory(thisRef.window.decorView).also { binding = it }
}
}
// 使用
class MyActivity : AppCompatActivity() {
val binding: ActivityMainBinding by ViewBindingDelegate(ActivityMainBinding::inflate)
}5.5 委托组合
kotlin
// 组合多个委托
class CompositeDelegate<T>(
private val delegates: List<ReadWriteProperty<Any?, T>>
) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return delegates.first().getValue(thisRef, property)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
delegates.forEach { it.setValue(thisRef, property, value) }
}
}
// 链式委托
class ChainDelegate<T>(
private val readDelegate: ReadOnlyProperty<Any?, T>,
private val writeDelegate: WriteOnlyProperty<Any?, T>
) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return readDelegate.getValue(thisRef, property)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
writeDelegate.setValue(thisRef, property, value)
}
}
// WriteOnlyProperty(自定义)
interface WriteOnlyProperty<in R, in T> {
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}6. 面试考点汇总
6.1 基础问题
Q1: 什么是委托属性?如何使用?
kotlin
// 答案要点:
// 1. 将属性的 getter/setter 委托给另一个对象
// 2. 使用 by 关键字
// 3. 委托类需要实现 getValue/setValue
// 4. 标准库提供 lazy、observable 等委托
// 定义
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "value"
}
}
// 使用
class Example {
var prop: String by Delegate()
}Q2: lazy 委托的原理是什么?
kotlin
// 答案要点:
// 1. 返回 Lazy<T> 接口
// 2. 首次访问时执行初始化 lambda
// 3. 结果被缓存
// 4. 三种线程安全模式
val value: String by lazy {
println("Computing...")
"Hello"
}
// 第一次访问:打印 "Computing..." 然后 "Hello"
// 后续访问:只返回 "Hello"Q3: observable 和 vetoable 的区别?
kotlin
// 答案要点:
// 1. observable:属性变化后通知
// 2. vetoable:可以拒绝属性更新
// 3. observable 返回 Unit
// 4. vetoable 返回 Boolean
// observable
var name by Delegates.observable("") { _, old, new ->
println("Changed from $old to $new")
}
// vetoable
var age by Delegates.vetoable(0) { _, _, new ->
new >= 0 // 拒绝负数
}6.2 进阶问题
Q4: 如何自定义委托属性?
kotlin
// 答案要点:
// 1. 实现 ReadWriteProperty 或 ReadOnlyProperty
// 2. 实现 getValue 和 setValue 方法
// 3. 使用 by 关键字应用委托
class NotNullVar<T> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Not initialized")
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}Q5: 委托属性的编译原理?
kotlin
// 答案要点:
// 1. 编译时创建委托对象实例
// 2. getter 转换为 delegate.getValue(this, ::prop)
// 3. setter 转换为 delegate.setValue(this, ::prop, value)
// 4. KProperty 提供属性元数据
// Kotlin
class Example {
var prop: String by Delegate()
}
// 编译后(伪代码)
class Example {
private val delegate = Delegate()
var prop: String
get() = delegate.getValue(this, ::prop)
set(value) = delegate.setValue(this, ::prop, value)
}Q6: provideDelegate 的作用?
kotlin
// 答案要点:
// 1. 在创建委托时调用
// 2. 可以返回不同的委托对象
// 3. 用于 ViewBinding 等场景
// 4. 操作符函数 provideDelegate
class ResourceProvider {
operator fun provideDelegate(
thisRef: Activity,
property: KProperty<*>
): ReadOnlyProperty<Activity, View> {
val view = thisRef.findViewById(property.name)
return Property { _, _ -> view }
}
}6.3 原理问题
Q7: lazy 的三种线程安全模式?
kotlin
// 答案要点:
// 1. SYNCHRONIZED:默认,使用锁,线程安全
// 2. PUBLICATION:可能多次计算,但返回相同结果
// 3. NONE:单线程,无锁,最快
val lazy1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { compute() }
val lazy2 by lazy(LazyThreadSafetyMode.PUBLICATION) { compute() }
val lazy3 by lazy(LazyThreadSafetyMode.NONE) { compute() }Q8: 委托属性的内存开销?
kotlin
// 答案要点:
// 1. 每个委托属性创建委托对象
// 2. 有额外的对象分配
// 3. lazy 委托只创建一次
// 4. observable 委托持有观察者引用
// 内存考虑
class Example {
// 每个实例都创建 Delegate 对象
var prop: String by Delegate()
// 可以使用伴生对象共享
companion object {
private val delegate = Delegate()
}
var prop2: String by delegate
}6.4 实战问题
Q9: 如何在 Android 中使用委托属性?
kotlin
// 答案要点:
// 1. lazy 用于延迟初始化
// 2. observable 用于 UI 绑定
// 3. map 用于参数解析
// 4. 自定义委托用于 ViewBinding
// lazy
class Repository {
private val database: Database by lazy {
Database.connect()
}
}
// observable
class ViewModel {
var userName: String by Delegates.observable("") { _, _, _ ->
notifyUiChanged()
}
}
// map
class Fragment : Fragment() {
val userId: String by arguments!!
}
// ViewBinding
class Activity : AppCompatActivity() {
val binding: ActivityMainBinding by ViewBindingDelegate()
}Q10: 委托属性与 lateinit 的区别?
kotlin
// 答案要点:
// 1. lateinit 用于 var,不能用于 val
// 2. lateinit 不能用于基本类型
// 3. lateinit 在赋值前访问抛异常
// 4. 委托更灵活,可以自定义行为
// lateinit
lateinit var view: View
// 委托
var view: View by NotNullVar()
val config: Config by lazy { Config() }Q11: 如何实现线程安全的委托?
kotlin
// 答案要点:
// 1. 使用 synchronized
// 2. 使用 volatile
// 3. 使用原子类
// 4. 使用 lazy 的 SYNCHRONIZED 模式
class ThreadSafeDelegate<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value: T = initialValue
private val lock = Any()
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
synchronized(lock) { return value }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
synchronized(lock) { this.value = value }
}
}最佳实践总结
✅ 推荐做法
kotlin
// 1. 使用 lazy 延迟初始化
val database: Database by lazy { Database.connect() }
// 2. 使用 observable 监听变化
var name by Delegates.observable("") { _, old, new ->
println("Changed: $old -> $new")
}
// 3. 使用 vetoable 验证
var age by Delegates.vetoable(0) { _, _, new -> new >= 0 }
// 4. 使用 map 解析参数
class User(map: Map<String, Any?>) {
val name: String by map
}
// 5. 自定义委托复用逻辑
class NotNullVar<T> : ReadWriteProperty<Any?, T> { ... }❌ 避免做法
kotlin
// 1. 避免过度使用委托
// 不是所有属性都需要委托
// 2. 避免复杂的委托逻辑
// 委托应该简单明了
// 3. 注意内存泄漏
// observable 持有观察者引用
// 4. 注意线程安全
// 多线程环境使用同步参考资料
最后更新:2026-04-14