美文网首页
kotlin语法糖实现

kotlin语法糖实现

作者: 沉迷学习_日渐发福 | 来源:发表于2018-11-18 22:30 被阅读0次

对于kotlin和java,两个语言都是在jvm上运行的,所以它们最终生产的字节码将会是一致的。对于kotlin的一些比较方便的语法糖,我们可以利用其等同的java代码,来验证其内部的实现。

字节码和.kt对应的.java文件

通过AndroidStudio的tool -> kotlin -> show kotlin bytecode,可以生产kt文件对应的字节码,然后在字节码文件上,选中Decompile,反编译字节码文件,可以生成对应的.java文件。

可空参数与非空参数

kotlin的参数定义时,必须标明是否可空。

 var callBack: String? = null
 var currentFlow:PayFlow = PayFlow.Idle

第一个参数表示可空的,第二个参数表示非空参数
其实在java中,就是对应以下的定义

@Nullable
private static String callBack;
@NotNull
private static final ReadWriteProperty currentFlow$delegate

其实kotlin实现非空参数,跟java通过注解@Nullable和@NotNull来实现是一样的。

object关键字来实现单例

object PayFlowManager {
}

对应的java实现为

public static final PayFlowManager INSTANCE;
static {
      PayFlowManager var0 = new PayFlowManager();
      INSTANCE = var0;
}

利用了static加载的方式,来创建单例。也就是我们常说的单例的饿汉实现。同时,这个创建出来的变量名为INSTANCE,所以我们java调用的方式都需要通过类名.INSTANCE来访问kt的单例。

lambda

kotlin中,支持传入lambda作为成员变量

var succeedViewAction: () -> Unit = {}

这个lambda表示当前接收空参数,并且返回值为空。在java中的表示为

 @NotNull
 private Function1 payResultAction;

这个Function1是一个接口,也就是说,kt的lambda对于java来说,就是一个接口。lambda每多一个参数,都有一个相对应的Function,后面的数字就表示参数的个数。

** 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 22 arguments. */
public interface Function22<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
}

也就是说,目前kt的最多支持的lambda的参数的个数是22个。
所以,在java中传递这个lambda,就是set这个接口的实现类,也就是匿名内部类。

payTypeParam.setPayResultAction(new Function1<Integer, Unit>() {
            @Override
            public Unit invoke(Integer integer) {
                ...
                return null;
            }
        });

companion object

在kt中,通常我们用companion object来作为静态成员的存储。

companion object {
       val PAY_SOURCE_NONE = 0
       val PAY_SOURCE_LIST = 1
       val PAY_SOURCE_ACTIVITY = 2
       val PAY_SOURCE_COMIC = 3
       val PAY_SOURCE_NOTICE = 4
       val PAY_SOURCE_LIVE = 5
       val PAY_SOURCE_VIP_CENTER = 6
       val PAY_SOURCE_PARTNER = 8
       val PAY_SOURCE_COMIC_LAYER = 9
   }

对应的java代码为:

public interface PaySource {
   PaySource.Companion Companion = PaySource.Companion.$$INSTANCE;
public static final class Companion {
      private static final int PAY_SOURCE_NONE = 0;
      private static final int PAY_SOURCE_LIST = 1;
      private static final int PAY_SOURCE_ACTIVITY = 2;
      private static final int PAY_SOURCE_COMIC = 3;
      private static final int PAY_SOURCE_NOTICE = 4;
      private static final int PAY_SOURCE_LIVE = 5;
      private static final int PAY_SOURCE_VIP_CENTER = 6;
      private static final int PAY_SOURCE_PARTNER = 8;
      private static final int PAY_SOURCE_COMIC_LAYER = 9;
      // $FF: synthetic field
      static final PaySource.Companion $$INSTANCE;
      static {
         PaySource.Companion var0 = new PaySource.Companion();
         $$INSTANCE = var0;
    }
    ...
    等对应的get和set方法
    }
}

也就是说,内部会生成一个Companion的静态内部类,同时生成一个这个静态内部类对应的实例。java调用时,将会直接调用这个Companion变量来访问静态方法和静态变量。

kotlin Extension

kt提供了一个插件,让我们可以在用到xml的地方直接用id进行访问,而不用再通过findViewById来初始化View,我们需要先导入对应的生成文件

import kotlinx.android.synthetic.main.activity_vip_recharge.*

在对应java实现中,我们可以知道其内部的实现

public View _$_findCachedViewById(int var1) {
      if (this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }

      View var2 = (View)this._$_findViewCache.get(var1);
      if (var2 == null) {
         var2 = this.findViewById(var1);
         this._$_findViewCache.put(var1, var2);
      }

      return var2;
   }

   public void _$_clearFindViewByIdCache() {
      if (this._$_findViewCache != null) {
         this._$_findViewCache.clear();
      }

   }

对于每一个通过id直接调用view的类,都会生成_$_findCachedViewById方法,在这个方法中,提供了findViewById的操作,同时会创建出一个HashMap作为缓存时,防止多次使用时重复的执行findViewById操作。

 ((ImageView)this._$_findCachedViewById(id.icBack)).setOnClickListener((OnClickListener)this);
      ((TextView)this._$_findCachedViewById(id.tradingRecord)).setOnClickListener((OnClickListener)this);
      ((KKLayoutButton)this._$_findCachedViewById(id.btnAction)).setOnClickListener((OnClickListener)this);
      ((TextView)this._$_findCachedViewById(id.autoContinue)).setOnClickListener((OnClickListener)this);

kt在每一个使用到id的地方,都将入侵式的替换代码,通过我们给定的id来调用findViewById。

lateinit关键字

对于一个我们保证肯定会在生命周期一开始就初始化的值,我们可以用lateinit来修饰

private lateinit var mMemberAutoContinueClose: ImageView

那么kt如何保证这个lateinit的有效性呢?

if (this.mMemberAutoContinueClose == null) {
         Intrinsics.throwUninitializedPropertyAccessException("mMemberAutoContinueClose");
      }

在每一次使用这个属性之前都会先做一次判空操作,一旦为空,将会直接抛出异常。

扩展函数

kt的一个非常牛逼的功能,其实就是扩展函数,我们可以扩展一些基础类的基本功能,比如说我们给Context扩展toast功能:

fun Context?.toast(@StringRes toastRes: Int) {
    if (this == null) {
        return
    }
    val text = getString(toastRes)
    toast(text)
}

对应的生成java代码:

public static final void toast(@Nullable Context $receiver, @StringRes int toastRes) {
      if ($receiver != null) {
         String text = $receiver.getString(toastRes);
         Intrinsics.checkExpressionValueIsNotNull(text, "text");
         toast($receiver, text);
      }
   }

也就是说,扩展函数的功能其实就是基于静态方法来实现的。被扩展类作为第一个入参,后续的参数就是扩展函数需要的参数。
而且,每一个扩展函数的文件,都会生成对应名称的class文件。比如说KotlinExt.kt将会生成KotlinExtKt这个类。最后java文件中,通过生成的类来访问静态方法。

相关文章

  • kotlin语法糖实现

    对于kotlin和java,两个语言都是在jvm上运行的,所以它们最终生产的字节码将会是一致的。对于kotlin的...

  • 3. Kotlin单例实现方式

    饿汉式 这个版本的实现,其实是个语法糖(Kotlin漫山遍野都是语法糖)。其真正的实现类似于这样 懒汉式加载 la...

  • Android日常开发Tips记录

    kotlin DCL单例 ?:等价于if(instance == null ){},.also为kotlin语法糖...

  • Kotlin语法糖

    一、Kotlin 支持三个引号 """ 扩起来的字符串,支持多行字符串,比如: 二、字符串模板字符串可以包含模板表...

  • kotlin 语法糖?

    唯品会那会,技术分享,正愁主题。刷圈看到老大分享的技术文章,关于kotlin的。猎奇之后,哎哟,挺好玩的。 庞然大...

  • Kotlin语法糖

    Kotlin语法糖 Kotlin 语言是一种新的静态类型编程语言,可运行于 JVM 环境同时也能用来开发 Andr...

  • kotlin语法糖

    kotlin withfun with(receiver: T, f: T.() -> R): R ...

  • Kotlin语法糖--基础

    不管你学习什么语言,开篇都是介绍基本类型,然后就是诸如控制流这种入门语法,随后就是对象、函数的使用,最后就是此语言...

  • Kotlin语法糖--开始

    谷歌宣布Kotlin成为Android官方开发语言已经4个多月了,相信你或多或少的已经开始接触Kotlin语言了。...

  • Kotlin语法糖总结

    一、前言 使用kotlin开发项目已经有一段时间,在使用kotlin的过程中,发现了许多很方便的语法糖,可以有效简...

网友评论

      本文标题:kotlin语法糖实现

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