kotlin by关键字实现委托属性与委托类
委托类
// 创建接口interface Base {
fun print()}
// 实现此接口的被委托的类class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }}
// 通过关键字 by 建立委托类class Derived(b: Base) : Base by b
fun main(args: Array) {
val b = BaseImpl(10)
Derived(b).print() // 输出 10}
class CountingSet3(
val innerSet: MutableSet = HashSet()
) : MutableSet by innerSet {
需要注意的是:
- CountingSet3 必须实现一个接口,而不能继承于一个类;
- innerSet 的类型必须是 CountingSet3 所实现接口的子类型;
- 可以直接在 by 创建委托对象,如下所示: 但是,这样的话,在 CountingSet4 类中无法获取到委托对象的引用了。
class CountingSet4(
) : MutableSet by HashSet() {
}
class CountingSet3(
val innerSet: MutableSet = HashSet()
) : MutableSet by innerSet {
var objectAdded = 0
override fun add(element: T): Boolean {
objectAdded++
return innerSet.add(element)
}
override fun addAll(elements: Collection): Boolean {
objectAdded += elements.size
return innerSet.addAll(elements)
}
}
fun main() {
val cset = CountingSet3()
cset.add(1)
cset.addAll(listOf(2, 2, 3))
println("${cset.objectAdded} objects were added, ${cset.size} remain")
}
其对应class反编译代码为
public final class CountingSet3 implements Set, KMutableSet {
private int objectAdded;
@NotNull
private final Set innerSet;
public final int getObjectAdded() {
return this.objectAdded;
}
public final void setObjectAdded(int var1) {
this.objectAdded = var1;
}
public boolean add(Object element) {
int var10001 = this.objectAdded++;
return this.innerSet.add(element);
}
public boolean addAll(@NotNull Collection elements) {
Intrinsics.checkNotNullParameter(elements, "elements");
this.objectAdded += elements.size();
return this.innerSet.addAll(elements);
}
@NotNull
public final Set getInnerSet() {
return this.innerSet;
}
public CountingSet3(@NotNull Set innerSet) {
Intrinsics.checkNotNullParameter(innerSet, "innerSet");
super();
this.innerSet = innerSet;
}
// $FF: synthetic method
public CountingSet3(Set var1, int var2, DefaultConstructorMarker var3) {
if ((var2 & 1) != 0) {
var1 = (Set)(new HashSet());
}
this(var1);
}
public CountingSet3() {
this((Set)null, 1, (DefaultConstructorMarker)null);
}
public int getSize() {
return this.innerSet.size();
}
// $FF: bridge method
public final int size() {
return this.getSize();
}
public void clear() {
this.innerSet.clear();
}
public boolean contains(Object element) {
return this.innerSet.contains(element);
}
public boolean containsAll(@NotNull Collection elements) {
Intrinsics.checkNotNullParameter(elements, "elements");
return this.innerSet.containsAll(elements);
}
public boolean isEmpty() {
return this.innerSet.isEmpty();
}
@NotNull
public Iterator iterator() {
return this.innerSet.iterator();
}
public boolean remove(Object element) {
return this.innerSet.remove(element);
}
public boolean removeAll(@NotNull Collection elements) {
Intrinsics.checkNotNullParameter(elements, "elements");
return this.innerSet.removeAll(elements);
}
public boolean retainAll(@NotNull Collection elements) {
Intrinsics.checkNotNullParameter(elements, "elements");
return this.innerSet.retainAll(elements);
}
public Object[] toArray() {
return CollectionToArray.toArray(this);
}
public Object[] toArray(Object[] var1) {
return CollectionToArray.toArray(this, var1);
}
}
委托属性
class Foo {
var p: Type by Delegate()
}
等价于
class Foo {
private val delegate = Delegate()
var p: Type
set(value: Type) = delegate.setValue(this, ..., value)
get() = delegate.getValue(this, ...)
}
实例如下
class Person6 {
var name: String by Delegate3()
var lastname: String by Delegate3()
var updateCount = 0
}
fun main() {
val person = Person6()
person.name = "peter"
person.lastname = "wang"
println("name=${person.name}")
println("lastname=${person.lastname}")
println("updateCount=${person.updateCount}")
}
/*
打印如下:
name=Peter-5
lastname=Wang-4
updateCount=2
*/
class Delegate3 : ReadWriteProperty {
var formattedString = ""
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return formattedString + "-" + formattedString.length
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
if (thisRef is Person6) {
thisRef.updateCount++
}
formattedString = value.lowercase().replaceFirstChar { it.uppercase() }
}
}
反编译后对应java代码如下
public final class Delegate3 implements ReadWriteProperty {
@NotNull
private String formattedString = "";
@NotNull
public final String getFormattedString() {
return this.formattedString;
}
public final void setFormattedString(@NotNull String var1) {
this.formattedString = var1;
}
@NotNull
public String getValue(@NotNull Object thisRef, @NotNull KProperty property) {
return this.formattedString + "-" + this.formattedString.length();
}
// $FF: synthetic method
// $FF: bridge method
public Object getValue(Object var1, KProperty var2) {
return this.getValue(var1, var2);
}
public void setValue(@NotNull Object thisRef, @NotNull KProperty property, @NotNull String value) {
if (thisRef instanceof Person6) {
((Person6)thisRef).setUpdateCount(((Person6)thisRef).getUpdateCount() + 1);
}
Delegate3 var10000 = this;
boolean var5 = false;
String var10001 = value.toLowerCase(Locale.ROOT);
Intrinsics.checkNotNullExpressionValue(var10001, "(this as java.lang.Strin….toLowerCase(Locale.ROOT)");
String var4 = var10001;
var5 = false;
CharSequence var6 = (CharSequence)var4;
boolean var7 = false;
if (var6.length() > 0) {
StringBuilder var20 = new StringBuilder();
char it = var4.charAt(0);
StringBuilder var15 = var20;
int var9 = false;
boolean var11 = false;
String var12 = String.valueOf(it);
boolean var13 = false;
if (var12 == null) {
throw new NullPointerException("null cannot be cast to non-null type java.lang.String");
}
String var19 = var12.toUpperCase(Locale.ROOT);
Intrinsics.checkNotNullExpressionValue(var19, "(this as java.lang.Strin….toUpperCase(Locale.ROOT)");
String var16 = var19;
var10000 = this;
var20 = var15.append(var16.toString());
byte var17 = 1;
boolean var18 = false;
if (var4 == null) {
throw new NullPointerException("null cannot be cast to non-null type java.lang.String");
}
String var10002 = var4.substring(var17);
Intrinsics.checkNotNullExpressionValue(var10002, "(this as java.lang.String).substring(startIndex)");
var10001 = var20.append(var10002).toString();
} else {
var10001 = var4;
}
var10000.formattedString = var10001;
}
// $FF: synthetic method
// $FF: bridge method
public void setValue(Object var1, KProperty var2, Object var3) {
this.setValue(var1, var2, (String)var3);
}
}
public final class Person6 {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{
(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Person6.class, "name", "getName()Ljava/lang/String;", 0)),
(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Person6.class, "lastname", "getLastname()Ljava/lang/String;", 0))};
@NotNull
private final Delegate3 name$delegate = new Delegate3();
@NotNull
private final Delegate3 lastname$delegate = new Delegate3();
private int updateCount;
@NotNull
public final String getName() {
return this.name$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setName(@NotNull String var1) {
this.name$delegate.setValue(this, $$delegatedProperties[0], var1);
}
@NotNull
public final String getLastname() {
return this.lastname$delegate.getValue(this, $$delegatedProperties[1]);
}
public final void setLastname(@NotNull String var1) {
this.lastname$delegate.setValue(this, $$delegatedProperties[1], var1);
}
public final int getUpdateCount() {
return this.updateCount;
}
public final void setUpdateCount(int var1) {
this.updateCount = var1;
}
}
lateinit与by lazy
如下写法会编译不通过
class Demo {
var value: String
fun printValue() {
println(value)
}}
改为
lateinit var value: String
运行抛异常
lateinit修饰的成员变量等价于
// 字节码等价代码
fun printValue() {
val tempValue = this.value
if(tempValue == null) {
throw UninitializedPropertyAccessException("lateinit property value has not been initialized")
}
println(tempValue)}
val lazyProp: String by lazy {
println("Hello,第一次调用才会执行我!")
"西哥!"
}
// 打印lazyProp 3次,查看结果
fun main() {
println(lazyProp)
println(lazyProp)
println(lazyProp)
}
Hello,第一次调用才会执行我!
西哥!
西哥!
西哥!
扩展函数与扩展属性
如果扩展函数和被扩展类中的成员函数有相同的接收类型、名字和参数,那么这种情况下 ** 总是取成员**。例如:
class Dog {
fun showName(){
print("Dog")
}
}
fun Dog.showName(){
print("Cat")
}
fun main(args: Array) {
Dog().showName()
}
如果我们调用 Dog 类的 showName(),它将输出“Dog”,而不是“Cat”
扩展函数实质上是调用了新生成的一个类的静态方法,如
fun String.times(t:Int){
val sb = StringBuilder()
for (i in 0 until t) {
sb.append(this)
}
println(sb.toString())}
``
其等价于
```kotlin
public final class TestObjectKt {
public static final void times(@NotNull String $receiver, int t) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
StringBuilder sb = new StringBuilder();
IntRange var10000 = RangesKt.until(0, t);
int i = var10000.getFirst();
int var4 = var10000.getLast();
if(i <= var4) {
while(true) {
sb.append($receiver);
if(i == var4) {
break;
}
++i;
}
}
String var5 = sb.toString();
System.out.println(var5);
}}
扩展属性
扩展属性不能初始化
//错误:扩展属性不能有初始化
val Snake.bbb = 1
扩展属性并没有field可以用来存储value,其实际作用是使用通过value来操作调用者,即this
fun main(args: Array) {
val str = "aa"
//没有backing field,不能存储值,其实际是通过setXXX(str,10)操作str
//输出:aa10
str.s = 10
//输出:2
println(str.s)}
var String.s: Int
get() = this.length
set(value){
//set方法并没有field可以用来存储value,
//其实际作用是使用通过value来操作调用者,即this
println(this.plus(value))
}
对应java
public final class ExtendsKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String str = "aa";
setS(str, 10);
int var2 = getS(str);
System.out.println(var2);
}
public static final int getS(@NotNull String $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.length();
}
public static final void setS(@NotNull String $receiver, int value) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
String var2 = $receiver + value;
System.out.println(var2);
}}
let,run,apply
let需要it指代统一的引用
run不需要it
apply可以有返回值
//let
val result = object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo()
1000
}
//with
val result = with(user, {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
})
l
//run
fun main(args: Array) {
val user = User("Kotlin", 1, "1111111")
val result = user.run {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
//apply
fun main(args: Array) {
val user = User("Kotlin", 1, "1111111")
val result = user.apply {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
//also
fun main(args: Array) {
val result = "testLet".also {
println(it.length)
1000
}
println(result)
}
Flow与Channel
Channel类似于阻塞队列
Flow类似于Rxjava
https://juejin.cn/post/6983673515526324237
fun produceAndConsume() {
GlobalScope.launch {
val channel = Channel()
val producer = GlobalScope.launch {
var i = 0
while (true) {
Log.i(tag, "生产者生产了:$i")
channel.send(i++)
delay(1000)
}
}
val consumer = GlobalScope.launch {
while (true) {
val element = channel.receive()
Log.i(tag, "消费者消费了:$element")
}
}
producer.join()
consumer.join()
}
}
//输出
I/ProduceAndConsume: 生产者生产了:0
I/ProduceAndConsume: 消费者消费了:0
I/ProduceAndConsume: 生产者生产了:1
I/ProduceAndConsume: 消费者消费了:1
I/ProduceAndConsume: 生产者生产了:2
I/ProduceAndConsume: 消费者消费了:2
I/ProduceAndConsume: 生产者生产了:3
I/ProduceAndConsume: 消费者消费了:3
Flow有以下特点:
- 冷数据流,不消费则不生产,这一点与Channel正相反:Channel的发送端并不依赖于接收端。
- Flow通过flowOn改变数据发射的线程,数据消费线程则由协程所在线程决定
- 与RxJava类似,支持通过catch捕获异常,通过onCompletion 回调完成
- Flow没有提供取消方法,可以通过取消Flow所在协程的方式来取消
lifecycleScope.launch {
flow {
for (i in 1..10) {
emit(i)
}
}.flowOn(Dispatchers.Main)
.catch {
//异常处理
}
.onCompletion {
//完成回调
}
.collect { num ->
// 具体的消费处理
// 只有collect时才会生产数据
// ...
}
}