Through the discussion and learning of the previous two articles, we have a clear understanding of the delegation of attributes. Let’s take a look at the actual application scenarios of delegated attributes today.
Behind property delegation
Before introducing the application scenario, let’s look back at the backside of property delegation and explore its implementation principle.
Since it is “entrustment”, its core is: Leave your work to others. For attributes, this is its reading and writing. Similar to the “delegated inheritance” of classes, the delegation of attributes must also have a “proxy object” to complete this work.
Here’s an example from a previous article:
class Delegate {<!-- --> operator fun getValue(thisRef: Owner?, property: KProperty<*>): String {<!-- --> return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Owner?, property: KProperty<*>, value: String) {<!-- --> println("$value has been assigned to '${property.name}' in $thisRef.") } } class Owner {<!-- --> var desc: String by Delegate() }
The desc variable of Owner
is delegated to the Delegate
object, and its corresponding Java code is as follows:
public final class Owner {<!-- --> // $FF: synthetic field static final KProperty[] $$delegatedProperties = new KProperty[]{<!-- -->(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Owner.class, "desc", "getDesc()Ljava/lang/ String;", 0))}; @NotNull private final Delegate desc$delegate = new Delegate(); @NotNull public final String getDesc() {<!-- --> return this.desc$delegate.getValue(this, $$delegatedProperties[0]); } public final void setDesc(@NotNull String var1) {<!-- --> Intrinsics.checkNotNullParameter(var1, "<set-?>"); this.desc$delegate.setValue(this, $$delegatedProperties[0], var1); } }
Did you see that Owner
internally generates a Delegate
object named desc$delegate
, which is the aforementioned “delegate object“. When reading the desc value, the getDesc()
method is called, and the getValue()
of the delegate object desc$delegate
is called internally. The first parameter entered is this — this is the “holder” mentioned in the previous article; the information of the delegated property is saved by an array KProperty
array.
When writing a value, call setDesc()
, which is similar to get and will not be repeated here.
So in general, the delegation of attributes still relies on a specific “agent” to complete, but this “agent” is automatically generated.
Why is
thisRef
empty for the delegate in the main() function?
Apply
Delegate to another property
The meaning of this application is that reading (writing) the value of a property depends on another property — difficult to understand? Just look at the code and it will be clear:
var topLevelInt: Int = 0 class ClassWithDelegate(val anotherClassInt: Int) class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {<!-- --> var delegatedToMember: Int by this::memberInt var delegatedToTopLevel: Int by ::topLevelInt val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt } var MyClass.extDelegated: Int by ::topLevelInt
The reading and writing of the value of delegatedToMember
is delegated to memberInt
, which means that reading and writing it is actually reading and writing memberInt
. Other variables have similar meanings.
Note the usage of ::
in it.
map store value
Map is “a collection of key-value pairs”. Using it as a delegated storage object for multiple variables is also an application scenario of delegation.
class User(map: Map<String, Any?>) {<!-- --> val name: String by map val age: Int by map }
The two variables name and age of the User
class are delegated to the parameter map. When constructing, attribute values are given and stored in the map:
val user = User(mapOf( "name" to "John Doe", "age" to 25 ))
Then you can use:
println(user.name) // Prints "John Doe" println(user. age) // Prints 25
Note that when constructing, the key value of the map must be the name of the attribute, otherwise an error will be reported:
val user = User(mapOf( "name2" to "John Doe", // change to name2 "age" to 25 ))
Exception in thread "main" java.util.NoSuchElementException: Key name is missing in the map. at kotlin.collections.MapsKt__MapWithDefaultKt.getOrImplicitDefaultNullable(MapWithDefault.kt:24) at User.getName(DelegationApplication.kt:2) at DelegationApplicationKt.main(DelegationApplication.kt:11)
Principle
Map’s delegation feature is not built-in, but implemented through “delegation extension” (before):
public inline operator fun <V, V1 : V> Map<in String, @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 = @Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
This is also an example of the standard library implemented by the extension method of the delegated property mentioned in the previous article. Naturally there are also setters:
@kotlin.internal.InlineOnly public inline operator fun <V> MutableMap<in String, in V>.setValue(thisRef: Any?, property: KProperty<*>, value: V) {<!-- --> this. put(property. name, value) }
Pay attention to this setter, there is a difference, it is an extension of MutableMap
– after all, if you want to write a value, you need to be mutable. Another example:
class User2(map: MutableMap<String, Any?>) {<!-- --> var name: String by map var age: Int by map }
Access and change the value:
val mutable: MutableMap<String, Any?> = mutableMapOf( "name" to "John Doe", "age" to 25 ) val user2 = User2(mutable) println(user2.name) println(user2. age) println(mutable["name"]) println(mutable["age"]) user2.name = "Jane Doe" user2.age = 30 println(user2.name) println(user2. age) println(mutable["name"]) println(mutable["age"]) }
result:
John Doe 25 John Doe 25 Jane Doe 30 Jane Doe 30
For the first visit, User2 has the same saved value as the incoming map; then, change the values of name and age directly through the object user2, and after the change is successful, the values in the map also change-because it was originally entrusted to it Well, value reading and writing are done by it!
Delegate of local variables
Local variables can also be delegated, such as lazy-loaded applications, to avoid unnecessary initialization:
fun example(computeFoo: () -> Foo) {<!-- --> val memoizedFoo by lazy(computeFoo) if (someCondition & amp; & amp; memoizedFoo.isValid()) {<!-- --> memoizedFoo. doSomething() } }
Because memoizedFoo is a lazy loading delegate, only when someCondition
is true, it will call computeFoo to construct the object; otherwise, it will be troublesome:
fun example(computeFoo: () -> Foo) {<!-- --> if (someCondition) {<!-- --> val memoizedFoo = computeFoo() if (memoizedFoo. isValid()) {<!-- --> memoizedFoo. doSomething() } } }
Summary
Well, the entrusted property has already been talked about here. See you next time!
Last
If you want to become an architect or want to break through the 20-30K salary range, then don’t be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.
If you have no direction, here I would like to share with you a set of “Advanced Notes on the Eight Major Modules of Android” written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.
Full set of video materials:
1. Interview Collection
2. Collection of source code analysis
3. Collection of open source frameworks
Welcome everyone to support with one click and three links. If you need the information in the article, you can directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓
PS: There is also a ChatGPT robot in the group, which can answer your work or technical questions