lambda 代替回调函数的本质

  1. package com.ssy
  2. class Main2 {
  3. companion object {
  4. @JvmStatic
  5. fun main(list: Array<String>) {
  6. var view = View()
  7. view.setOnClickListener(object : OnClickListener {
  8. override fun onClick(view: View) {
  9. println("触发了 onClick 方法 ${view.toString()}")
  10. }
  11. })
  12. view.click()
  13. var view2 = View2()
  14. view2.setOnClickListener {
  15. println("触发了 onClick 方法 $it")
  16. }
  17. view2.click()
  18. }
  19. }
  20. }
  21. class View {
  22. var clickListener: OnClickListener? = null;
  23. fun setOnClickListener(clickListener: OnClickListener) {
  24. this.clickListener = clickListener;
  25. }
  26. fun click() {
  27. clickListener?.onClick(this)
  28. }
  29. override fun toString(): String {
  30. return "View"
  31. }
  32. }
  33. //本质上是想传递onClick方法的,但是java不能传递方法,只能用对象来包裹,去传递
  34. interface OnClickListener {
  35. fun onClick(view: View)
  36. }
  37. class View2 {
  38. var onClick: ((View2) -> Unit)? = null
  39. fun click() {
  40. onClick?.invoke(this@View2)
  41. }
  42. fun setOnClickListener(onClick: (View2) -> Unit) {
  43. this.onClick = onClick
  44. }
  45. override fun toString(): String {
  46. return "View2"
  47. }
  48. }
public final class Main2 {
    @NotNull
    public static final Companion Companion = new Companion((DefaultConstructorMarker) null);

    @JvmStatic
    public static final void main(@NotNull String[] list) {
        Companion.main(list);
    }
}
public final class Main2$Companion {
    private Main2$Companion() {
    }

    public /* synthetic */ Main2$Companion(DefaultConstructorMarker $constructor_marker) {
        this();
    }

    @JvmStatic
    public final void main(@NotNull String[] list) {
        Intrinsics.checkNotNullParameter(list, "list");
        View2 view2 = new View2();
        view2.setOnClickListener(main.1.INSTANCE);
        view2.click();
    }
}
final class Main2$Companion$main$1 extends Lambda implements Function1<View2, Unit> {
    public static final Main2$Companion$main$1 INSTANCE = new Main2$Companion$main$1();

    Main2$Companion$main$1() {
        super(1);
    }

    public /* bridge */ /* synthetic */ Object invoke(Object obj) {
        invoke((View2) obj);
        return Unit.INSTANCE;
    }

    public final void invoke(@NotNull View2 it) {
        Intrinsics.checkNotNullParameter(it, "it");
        System.out.println((Object) ("触发了 onClick 方法 " + it));
    }
}
public final class View2 {
    @Nullable
    private Function1<? super View2, Unit> onClick;

    /* JADX DEBUG: Type inference failed for r0v0. Raw type applied. Possible types: kotlin.jvm.functions.Function1<? super com.ssy.View2, kotlin.Unit>, kotlin.jvm.functions.Function1<com.ssy.View2, kotlin.Unit> */
    @Nullable
    public final Function1<View2, Unit> getOnClick() {
        return this.onClick;
    }

    public final void setOnClick(@Nullable Function1<? super View2, Unit> function1) {
        this.onClick = function1;
    }

    public final void click() {
        Function1<? super View2, Unit> function1 = this.onClick;
        if (function1 != null) {
            Unit unit = (Unit) function1.invoke(this);
        }
    }

    public final void setOnClickListener(@NotNull Function1<? super View2, Unit> function1) {
        Intrinsics.checkNotNullParameter(function1, "onClick");
        this.onClick = function1;
    }

    @NotNull
    public String toString() {
        return "View2";
    }
}

通过查看反编译后的java源码,我们发现kotlin的这些便利,完全是语法糖去包装的。
通过黑魔法生成符合Jvm的代码。
所谓的传递方法,其实也是用对来包装的

我们来看看 Function1 是什么?原来就是一个

public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}

这里就设计到了 operator 操作符重载 () 相当于 invoke()

class ClickAction{
    operator fun invoke(){
        println("invoke~~~~~")
    }
}

var  click =  ClickAction()
click()

> Task :Main2.main()
invoke~~~~~
package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2): R
}
/** A function that takes 3 arguments. */
public interface Function3<in P1, in P2, in P3, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2, p3: P3): R
}
/** A function that takes 4 arguments. */
public interface Function4<in P1, in P2, in P3, in P4, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4): R
}

通过源码我们知道了,其实kotlin 的传递方法,也是通过我们熟悉的接口方式去实现。
首先他有个接口池,里面有各种参数的方法。通过编译器匹配到我们对应的接口和方法,通过编译代替我们去写模板,最后就是我们看到的了。

这里语法糖真的就是一个障眼法,给我们编程最大的方便,背后,它去通过模板生成我们平时要写的代码。
所以koltin是一门很实用的语言。尽可能减少我们编写的代码量,这样可以减少错误,也可以通过模板去规范我们平时不容易规范的编程习惯。

协程的真面目

kotlin 代码

class main3 {

    companion object {
        @JvmStatic
        fun main(array: Array<String>) {
            GlobalScope.launch {
                println("${Thread.currentThread().id}  ${Thread.currentThread().name}")
                getData()
            }
            Thread.sleep(5000)
        }
    }
}
suspend fun getData() = withContext(Dispatchers.IO) {
    delay(3000)
    val cat = Cat("xiao", 1)
    println("${Thread.currentThread().id}  ${Thread.currentThread().name}")
    cat
}

data class Cat(val name: String, val age: Int)

反编译后的java代码

1、data 类 Cat

public final class Cat {
    private final int age;
    @NotNull
    private final String name;

    public static /* synthetic */ Cat copy$default(Cat cat, String str, int i, int i2, Object obj) {
        if ((i2 & 1) != 0) {
            str = cat.name;
        }
        if ((i2 & 2) != 0) {
            i = cat.age;
        }
        return cat.copy(str, i);
    }

    @NotNull
    public final String component1() {
        return this.name;
    }

    public final int component2() {
        return this.age;
    }

    @NotNull
    public final Cat copy(@NotNull String name2, int age2) {
        Intrinsics.checkNotNullParameter(name2, "name");
        return new Cat(name2, age2);
    }

    public boolean equals(@Nullable Object obj) {
        if (this != obj) {
            if (obj instanceof Cat) {
                Cat cat = (Cat) obj;
                if (!Intrinsics.areEqual(this.name, cat.name) || this.age != cat.age) {
                    return false;
                }
            }
            return false;
        }
        return true;
    }

    public int hashCode() {
        String str = this.name;
        return ((str != null ? str.hashCode() : 0) * 31) + Integer.hashCode(this.age);
    }

    @NotNull
    public String toString() {
        return "Cat(name=" + this.name + ", age=" + this.age + ")";
    }

    public Cat(@NotNull String name2, int age2) {
        Intrinsics.checkNotNullParameter(name2, "name");
        this.name = name2;
        this.age = age2;
    }

    public final int getAge() {
        return this.age;
    }

    @NotNull
    public final String getName() {
        return this.name;
    }
}

main3

public final class main3 {
    @NotNull
    public static final Companion Companion = new Companion((DefaultConstructorMarker) null);

    @JvmStatic
    public static final void main(@NotNull String[] array) {
        Companion.main(array);
    }
}

main3$Companion

public final class main3$Companion {
    private main3$Companion() {
    }

    public /* synthetic */ main3$Companion(DefaultConstructorMarker $constructor_marker) {
        this();
    }

    @JvmStatic
    public final void main(@NotNull String[] array) {
        Intrinsics.checkNotNullParameter(array, "array");
        BuildersKt.launch$default(GlobalScope.INSTANCE, (CoroutineContext) null, (CoroutineStart) null, new main.1((Continuation) null), 3, (Object) null);
        Thread.sleep(5000);
    }
}
final class main3$Companion$main$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
    int label;

    main3$Companion$main$1(Continuation continuation) {
        super(2, continuation);
    }

    @NotNull
    public final Continuation<Unit> create(@Nullable Object value, @NotNull Continuation<?> continuation) {
        Intrinsics.checkNotNullParameter(continuation, "completion");
        return new main3$Companion$main$1(continuation);
    }

    public final Object invoke(Object obj, Object obj2) {
        return create(obj, (Continuation) obj2).invokeSuspend(Unit.INSTANCE);
    }

    @Nullable
    public final Object invokeSuspend(@NotNull Object obj) {
        Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();
        switch (this.label) {
            case 0:
                ResultKt.throwOnFailure(obj);
                StringBuilder sb = new StringBuilder();
                Thread currentThread = Thread.currentThread();
                Intrinsics.checkNotNullExpressionValue(currentThread, "Thread.currentThread()");
                StringBuilder append = sb.append(currentThread.getId()).append("  ");
                Thread currentThread2 = Thread.currentThread();
                Intrinsics.checkNotNullExpressionValue(currentThread2, "Thread.currentThread()");
                System.out.println((Object) append.append(currentThread2.getName()).toString());
                this.label = 1;
                if (Main3Kt.getData(this) == coroutine_suspended) {
                    return coroutine_suspended;
                }
                break;
            case 1:
                ResultKt.throwOnFailure(obj);
                break;
            default:
                throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
        }
        return Unit.INSTANCE;
    }
}
public final class Main3Kt {
    @Nullable
    public static final Object getData(@NotNull Continuation<? super Cat> continuation) {
        return BuildersKt.withContext(Dispatchers.getIO(), new getData.2((Continuation) null), continuation);
    }
}
final class Main3Kt$getData$2 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Cat>, Object> {
    int label;

    Main3Kt$getData$2(Continuation continuation) {
        super(2, continuation);
    }

    @NotNull
    public final Continuation<Unit> create(@Nullable Object value, @NotNull Continuation<?> continuation) {
        Intrinsics.checkNotNullParameter(continuation, "completion");
        return new Main3Kt$getData$2(continuation);
    }

    public final Object invoke(Object obj, Object obj2) {
        return create(obj, (Continuation) obj2).invokeSuspend(Unit.INSTANCE);
    }

    @Nullable
    public final Object invokeSuspend(@NotNull Object obj) {
        Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();
        switch (this.label) {
            case 0:
                ResultKt.throwOnFailure(obj);
                this.label = 1;
                if (DelayKt.delay(3000, this) == coroutine_suspended) {
                    return coroutine_suspended;
                }
                break;
            case 1:
                ResultKt.throwOnFailure(obj);
                break;
            default:
                throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
        }
        Cat cat = new Cat("xiao", 1);
        StringBuilder sb = new StringBuilder();
        Thread currentThread = Thread.currentThread();
        Intrinsics.checkNotNullExpressionValue(currentThread, "Thread.currentThread()");
        StringBuilder append = sb.append(currentThread.getId()).append("  ");
        Thread currentThread2 = Thread.currentThread();
        Intrinsics.checkNotNullExpressionValue(currentThread2, "Thread.currentThread()");
        System.out.println((Object) append.append(currentThread2.getName()).toString());
        return cat;
    }
}