我的编程空间,编程开发者的网络收藏夹
学习永远不晚

研究学习Kotlin的方法有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

研究学习Kotlin的方法有哪些

这篇文章将为大家详细讲解有关研究学习Kotlin的方法有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

Kotlin是一门让人感到很舒服的语言,相比Java来说,它更加简洁,省去了琐琐碎碎的语法工作,同时了提供了类似Lambda,String  template,Null Safe Operator等特性。让开发者用起来得心应手。

普通的Java/Android程序员通常只需要很短的时间就能快速使用Kotlin。综合Kotlin的诸多优点,加上Flipboard美国团队自2015年已引入Kotlin,Flipboard中国团队也已经开始采用Kotlin来作为Android主要开发语言。

虽然Kotlin使用简单快捷,然而由于自己的深入研究的习惯导致每接触到Kotlin的新功能,就马不停蹄的研究它的本质,这里总结一下关于如何研究Kotlin的一些方法来快速研究掌握Kotlin。

到底研究什么

比如Kotlin中提供了一种类型叫做Object,使用它我们可以快速实现单例模式的应用。代码特别的简单

object AppSettings {  }

那么问题来了,kotlin这个object类型的类是如何实现的呢,Null安全操作符的实现原理,Lambda表达式是基于内部类还是真正的Lambda,这些问题就是我们要研究的对象。

怎么研究

  • Kotlin和Java都是运行在JVM上,但是实际上JVM并不认识Java和Kotlin,因为它只和bytecode(即class文件)打交道。

  • 因而通过研究bytecode,我们是可以了解Kotlin的一些深入原理的

  • 由于同一份bytecode反编译成java和kotlin文件是等价的,所以将kotlin编译后的class文件反编译成Java,也是具有参考和研究价值的。

实践方法有哪些

  • 利用Kotlin插件

  • 利用kotlinc,javap等工具

一些实践

Null Safe Operator实现原理

在Java中,我们经常会遇到空指针的问题,Kotlin特意增加了一个空指针安全操作符?。使用起来如下

fun testNullSafeOperator(string: String?) {     System.out.println(string?.toCharArray()?.getOrNull(10)?.hashCode()) }

当我们进行这样的调用时

testNullSafeOperator(null) testNullSafeOperator("12345678901") testNullSafeOperator("123")

得到的输出结果为

null 49 null

从结果可见,并没有像Java那样抛出NullPointerException,而是遇到空指针则不继续执行了。

那么Kotlin的这个空指针安全操作符是如何工作的呢,我们可以借助IntelliJ IDE的Kotlin插件来辅助我们研究,步骤如下

  • 使用IntelliJ IDE打开一个待研究的Kotlin文件(需确保Kotlin插件已安装)

  • 按照下图依次点击至Show Kotlin Bytecode

研究学习Kotlin的方法有哪些

  • 上面的步骤操作后,会得到这样的bytecode

// access flags 0x19   public final static testNullSafeOperator(Ljava/lang/String;)V     @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0    L0     LINENUMBER 11 L0     GETSTATIC java/lang/System.out : Ljava/io/PrintStream;     ALOAD 0     DUP     IFNULL L1   //对string字符串判空     INVOKESTATIC kotlin/text/StringsKt.toCharArray (Ljava/lang/String;)[C     DUP     IFNULL L1  //对CharArray判空     BIPUSH 10     INVOKESTATIC kotlin/collections/ArraysKt.getOrNull ([CI)Ljava/lang/Character;     DUP     IFNULL L1  //对Char判空     INVOKEVIRTUAL java/lang/Object.hashCode ()I     INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;     GOTO L2    L1     POP     ACONST_NULL    L2     INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V    L3     LINENUMBER 12 L3     RETURN    L4     LOCALVARIABLE string Ljava/lang/String; L0 L4 0     MAXSTACK = 3     MAXLOCALS = 1 }

由字节码分析可见,其实所谓的 空指针安全操作符其实内部就是以此判空来确保不出现空指针  ,如果字节码不好理解,那我们使用上面的Decompile功能,将bytecode转成Java,如图操作

研究学习Kotlin的方法有哪些

反编译后得到的Java代码为

public static final void testNullSafeOperator(@Nullable String string) {       PrintStream var10000;       Integer var5;       label18: {          var10000 = System.out;          if(string != null) {             PrintStream var2 = var10000;             if(string == null) {                throw new TypeCastException("null cannot be cast to non-null type java.lang.String");             }              char[] var4 = ((String)string).toCharArray();             Intrinsics.checkExpressionValueIsNotNull(var4, "(this as java.lang.String).toCharArray()");             char[] var3 = var4;             var10000 = var2;             if(var3 != null) {                Character var10001 = ArraysKt.getOrNull(var3, 10);                if(var10001 != null) {                   var5 = Integer.valueOf(var10001.hashCode());                   break label18;                }             }          }           var5 = null;       }        var10000.println(var5);    }

这样读起来是不是更加容易理解呢。

Object类型研究

这里我们回到Object类型,还是再举个例子看看如何使用

//这是定义 object AppSettings {     fun updateConfig() {         //do some updating work     } }

关于应用也很简单

//在Kotlin文件中调用 AppSettings.updateConfig()  //在Java文件中调用 AppSettings.INSTANCE.updateConfig();

我们先看一下AppSettings的字节码文件

// ================AppSettings.class ================= // class version 50.0 (50) // access flags 0x31 public final class AppSettings {   // access flags 0x11   public final updateConfig()V    L0     LINENUMBER 7 L0     RETURN    L1     LOCALVARIABLE this LAppSettings; L0 L1 0     MAXSTACK = 0     MAXLOCALS = 1    // access flags 0x2   private <init>()V    L0     LINENUMBER 4 L0     ALOAD 0     INVOKESPECIAL java/lang/Object.<init> ()V     ALOAD 0     CHECKCAST AppSettings     PUTSTATIC AppSettings.INSTANCE : LAppSettings;     RETURN    L1     LOCALVARIABLE this LAppSettings; L0 L1 0     MAXSTACK = 1     MAXLOCALS = 1    // access flags 0x19   public final static LAppSettings; INSTANCE    // access flags 0x8   static <clinit>()V    L0     LINENUMBER 4 L0     //静态代码块中实例化,即类加载时便开始实例化     NEW AppSettings     INVOKESPECIAL AppSettings.<init> ()V     RETURN     MAXSTACK = 1     MAXLOCALS = 0    @Lkotlin/Metadata;(mv={1, 1, 5}, bv={1, 0, 1}, k=1, d1={"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\n\u0002\u0010\u0002\n\u0000\u0008\u00c6\u0002\u0018\u00002\u00020\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004\u00a8\u0006\u0005"}, d2={"LAppSettings;", "", "()V", "updateConfig", "", "production sources for module KotlinObject"})   // compiled from: AppSettings.kt }

由此可见,Kotlin的object也就是Java的单例模式的实现,在静态代码块初始化实例。如果字节码没有看懂的话,可以尝试反编译成Java代码来详细研究。

Lambda表达式研究

除此之外,Kotlin也是支持了Lambda表达式的。由于并非所有的JVM版本都支持invokedynamic(Lambda表达式依赖的字节码指令),比如Java  6的JVM,这其中就包含了许多安卓设备。所以我们怀疑Kotlin可能是像Scala那样将lambda表达式转换成了匿名内部类。

一个简单的Lambda表达式例子

class Test {     fun testObservable() {         val observable = Observable()         observable.addObserver { o, arg ->             System.out.println("$o $arg")         }     } }

我们使用插件同样查看bytecode

// ================Test.class ================= // class version 50.0 (50) // access flags 0x31 public final class Test {    // access flags 0x11   public final testObservable()V    L0     LINENUMBER 8 L0     NEW java/util/Observable     DUP     INVOKESPECIAL java/util/Observable.<init> ()V     ASTORE 1    L1     LINENUMBER 9 L1     ALOAD 1     GETSTATIC Test$testObservable$1.INSTANCE : LTest$testObservable$1;  //这里就是使用了匿名内部类(常常包含$字符)     CHECKCAST java/util/Observer     INVOKEVIRTUAL java/util/Observable.addObserver (Ljava/util/Observer;)V    L2     LINENUMBER 12 L2     RETURN    L3     LOCALVARIABLE observable Ljava/util/Observable; L1 L3 1     LOCALVARIABLE this LTest; L0 L3 0     MAXSTACK = 2     MAXLOCALS = 2    // access flags 0x1   public <init>()V    L0     LINENUMBER 6 L0     ALOAD 0     INVOKESPECIAL java/lang/Object.<init> ()V     RETURN    L1     LOCALVARIABLE this LTest; L0 L1 0     MAXSTACK = 1     MAXLOCALS = 1    @Lkotlin/Metadata;(mv={1, 1, 5}, bv={1, 0, 1}, k=1, d1={"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\n\u0002\u0010\u0002\n\u0000\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004\u00a8\u0006\u0005"}, d2={"LTest;", "", "()V", "testObservable", "", "production sources for module KotlinObject"})   // access flags 0x18   final static INNERCLASS Test$testObservable$1 null null   // compiled from: Space.kt }   // ================Test$testObservable$1.class ================= // class version 50.0 (50) // access flags 0x30 //生成的匿名内部类,规则为  当前的类名$当前的方法名$匿名内部类序号 final class Test$testObservable$1 implements java/util/Observer  {    // access flags 0x11   public final update(Ljava/util/Observable;Ljava/lang/Object;)V    L0     LINENUMBER 10 L0     GETSTATIC java/lang/System.out : Ljava/io/PrintStream;     NEW java/lang/StringBuilder     DUP     INVOKESPECIAL java/lang/StringBuilder.<init> ()V     ALOAD 1     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;     LDC " "     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;     ALOAD 2     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;     INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;     INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V    L1     LINENUMBER 11 L1     RETURN    L2     LOCALVARIABLE this LTest$testObservable$1; L0 L2 0     LOCALVARIABLE o Ljava/util/Observable; L0 L2 1     LOCALVARIABLE arg Ljava/lang/Object; L0 L2 2     MAXSTACK = 3     MAXLOCALS = 3    // access flags 0x0   <init>()V     ALOAD 0     INVOKESPECIAL java/lang/Object.<init> ()V     RETURN     MAXSTACK = 1     MAXLOCALS = 1    // access flags 0x19   public final static LTest$testObservable$1; INSTANCE    // access flags 0x8   static <clinit>()V     NEW Test$testObservable$1     DUP     INVOKESPECIAL Test$testObservable$1.<init> ()V     PUTSTATIC Test$testObservable$1.INSTANCE : LTest$testObservable$1;     RETURN     MAXSTACK = 2     MAXLOCALS = 0    @Lkotlin/Metadata;(mv={1, 1, 5}, bv={1, 0, 1}, k=3, d1={"\u0000\u0016\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\u0008\u0002\n\u0002\u0010\u0000\n\u0000\u0010\u0000\u001a\u00020\u00012\u000e\u0010\u0002\u001a\n \u0004*\u0004\u0018\u00010\u00030\u00032\u000e\u0010\u0005\u001a\n \u0004*\u0004\u0018\u00010\u00060\u0006H\n\u00a2\u0006\u0002\u0008\u0007"}, d2={"<anonymous>", "", "o", "Ljava/util/Observable;", "kotlin.jvm.PlatformType", "arg", "", "update"})   OUTERCLASS Test testObservable ()V   // access flags 0x18   final static INNERCLASS Test$testObservable$1 null null   // compiled from: Space.kt }

分析字节码可以看到有两个class文件,因此可以推断出Kotlin的Lambda表达式目前是一种基于内部类的语法糖实现。

除此之外,我们还可以使用kotlinc(Kotlin编译器来验证)

kotlinc Test.kt

执行完成后,查看生成的class文件

ls | grep ^Test Test$testObservable$1.class Test.class Test.kt

当然,我们还可以使用javap同样实现查看bytecode的功能,即 javap -c className 。

除此之外,我们还可以利用上面的方法研究如下Kotlin的特性

  • lazy初始化

  • when表达式

  • 方法引用

关于研究学习Kotlin的方法有哪些就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

研究学习Kotlin的方法有哪些

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

研究学习Kotlin的方法有哪些

这篇文章将为大家详细讲解有关研究学习Kotlin的方法有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Kotlin是一门让人感到很舒服的语言,相比Java来说,它更加简洁,省去了琐琐碎碎
2023-06-17

大数据对科学研究的影响有哪些

本篇内容介绍了“大数据对科学研究的影响有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  著名数据库专家吉姆·格雷(Jim Gray)博
2023-06-02

ASP.NET的学习方法有哪些

本篇内容介绍了“ASP.NET的学习方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!如果你已经有较多的面向对象开发经验,跳过以下这两
2023-06-17

学习laravel的方法有哪些

本篇内容介绍了“学习laravel的方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!学习 Laravel 更有效率的七个建议随着社区
2023-06-25

Python学习方法有哪些

本篇内容主要讲解“Python学习方法有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python学习方法有哪些”吧!  1、找简单易懂、例程比较好的教程,从头看到结尾,不要看很多本,专注于
2023-06-01

TensorFlow中的集成学习方法有哪些

TensorFlow中常用的集成学习方法包括:随机森林(Random Forest):随机森林是一种基于决策树的集成学习方法,通过构建多个决策树来提高预测准确度。梯度提升树(Gradient Boosting Tree):梯度提升树是一种迭
TensorFlow中的集成学习方法有哪些
2024-03-01

Python的学习方向有哪些

本篇内容介绍了“Python的学习方向有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、Python基础语法、python字符串解析、
2023-06-02

Centos的学习路线有哪些方面

这篇文章主要介绍“Centos的学习路线有哪些方面”,在日常操作中,相信很多人在Centos的学习路线有哪些方面问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Centos的学习路线有哪些方面”的疑惑有所帮助!
2023-06-10

Kotlin语法 与 Java语法有哪些不同的地方

这篇文章给大家介绍Kotlin语法 与 Java语法有哪些不同的地方,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Kotlin 与 Java基本语法对比Kotlin比Java更年轻,但它是一个非常有前途的编程语言,它的
2023-05-31

常用的机器学习算法有哪些

常用的机器学习算法有以下几种:1. 线性回归(Linear Regression):通过线性模型进行回归分析。2. 逻辑回归(Logistic Regression):通过逻辑函数进行二分类分析。3. 决策树(Decision Tree):
2023-09-21

常用的深度学习算法有哪些

常用的深度学习算法有以下几种:1. 卷积神经网络(Convolutional Neural Network, CNN):用于图像识别和处理任务。2. 递归神经网络(Recurrent Neural Network, RNN):用于序列数据的
2023-10-08

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录