美文网首页
kotlin语法糖以及原理

kotlin语法糖以及原理

作者: taoyyyy | 来源:发表于2022-11-22 09:08 被阅读0次

    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<String>) {
        val b = BaseImpl(10)
        Derived(b).print() // 输出 10}
    
    
    class CountingSet3<T>(
        val innerSet: MutableSet<T> = HashSet<T>()
    ) : MutableSet<T> by innerSet {
    
    

    需要注意的是:

    • CountingSet3 必须实现一个接口,而不能继承于一个类;
    • innerSet 的类型必须是 CountingSet3 所实现接口的子类型;
    • 可以直接在 by 创建委托对象,如下所示: 但是,这样的话,在 CountingSet4 类中无法获取到委托对象的引用了。
    class CountingSet4<T>(
    ) : MutableSet<T> by HashSet<T>() {
    }
    
    
    class CountingSet3<T>(
        val innerSet: MutableSet<T> = HashSet<T>()
    ) : MutableSet<T> by innerSet {
        var objectAdded = 0
        override fun add(element: T): Boolean {
            objectAdded++
            return innerSet.add(element)
        }
    
    
        override fun addAll(elements: Collection<T>): Boolean {
            objectAdded += elements.size
            return innerSet.addAll(elements)
        }
    }
    
    
    fun main() {
        val cset = CountingSet3<Int>()
        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<Any, String> {
        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<String>) {
        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<String>) {
        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<String>) {
        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<String>) {
        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<String>) {
        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<Int>()
    
    
                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有以下特点:

    1. 冷数据流,不消费则不生产,这一点与Channel正相反:Channel的发送端并不依赖于接收端。
    2. Flow通过flowOn改变数据发射的线程,数据消费线程则由协程所在线程决定
    3. 与RxJava类似,支持通过catch捕获异常,通过onCompletion 回调完成
    4. Flow没有提供取消方法,可以通过取消Flow所在协程的方式来取消
    lifecycleScope.launch {
        flow {
            for (i in 1..10) {
                emit(i)
            }
        }.flowOn(Dispatchers.Main)
            .catch {
                //异常处理
            }
            .onCompletion {
                //完成回调
            }
            .collect { num ->
                // 具体的消费处理
                // 只有collect时才会生产数据
                // ...
            }
    }
    

    相关文章

      网友评论

          本文标题:kotlin语法糖以及原理

          本文链接:https://www.haomeiwen.com/subject/suigxdtx.html