自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

研究學(xué)習(xí)Kotlin的一些方法

開發(fā) 后端
Kotlin是一門讓人感到很舒服的語言,相比Java來說,它更加簡潔,省去了瑣瑣碎碎的語法工作,同時了提供了類似Lambda,String template,Null Safe Operator等特性。讓開發(fā)者用起來得心應(yīng)手。

Kotlin是一門讓人感到很舒服的語言,相比Java來說,它更加簡潔,省去了瑣瑣碎碎的語法工作,同時了提供了類似Lambda,String template,Null Safe Operator等特性。讓開發(fā)者用起來得心應(yīng)手。

普通的Java/Android程序員通常只需要很短的時間就能快速使用Kotlin。綜合Kotlin的諸多優(yōu)點,加上Flipboard美國團隊自2015年已引入Kotlin,F(xiàn)lipboard中國團隊也已經(jīng)開始采用Kotlin來作為Android主要開發(fā)語言。

雖然Kotlin使用簡單快捷,然而由于自己的深入研究的習(xí)慣導(dǎo)致每接觸到Kotlin的新功能,就馬不停蹄的研究它的本質(zhì),這里總結(jié)一下關(guān)于如何研究Kotlin的一些方法來快速研究掌握Kotlin。

到底研究什么

比如Kotlin中提供了一種類型叫做Object,使用它我們可以快速實現(xiàn)單例模式的應(yīng)用。代碼特別的簡單

 

  1. object AppSettings {  

那么問題來了,kotlin這個object類型的類是如何實現(xiàn)的呢,Null安全操作符的實現(xiàn)原理,Lambda表達式是基于內(nèi)部類還是真正的Lambda,這些問題就是我們要研究的對象。

怎么研究

  • Kotlin和Java都是運行在JVM上,但是實際上JVM并不認識Java和Kotlin,因為它只和bytecode(即class文件)打交道。
  • 因而通過研究bytecode,我們是可以了解Kotlin的一些深入原理的
  • 由于同一份bytecode反編譯成java和kotlin文件是等價的,所以將kotlin編譯后的class文件反編譯成Java,也是具有參考和研究價值的。

實踐方法有哪些

  • 利用Kotlin插件
  • 利用kotlinc,javap等工具

一些實踐

Null Safe Operator實現(xiàn)原理

在Java中,我們經(jīng)常會遇到空指針的問題,Kotlin特意增加了一個空指針安全操作符?。使用起來如下

 

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

當(dāng)我們進行這樣的調(diào)用時

 

  1. testNullSafeOperator(null
  2. testNullSafeOperator("12345678901"
  3. testNullSafeOperator("123"

得到的輸出結(jié)果為

 

  1. null 
  2. 49 
  3. null 

從結(jié)果可見,并沒有像Java那樣拋出NullPointerException,而是遇到空指針則不繼續(xù)執(zhí)行了。

那么Kotlin的這個空指針安全操作符是如何工作的呢,我們可以借助IntelliJ IDE的Kotlin插件來輔助我們研究,步驟如下

  • 使用IntelliJ IDE打開一個待研究的Kotlin文件(需確保Kotlin插件已安裝)
  • 按照下圖依次點擊至Show Kotlin Bytecode

研究學(xué)習(xí)Kotlin的一些方法

  • 上面的步驟操作后,會得到這樣的bytecode

 

  1. // access flags 0x19 
  2.   public final static testNullSafeOperator(Ljava/lang/String;)V 
  3.     @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0 
  4.    L0 
  5.     LINENUMBER 11 L0 
  6.     GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
  7.     ALOAD 0 
  8.     DUP 
  9.     IFNULL L1   //對string字符串判空 
  10.     INVOKESTATIC kotlin/text/StringsKt.toCharArray (Ljava/lang/String;)[C 
  11.     DUP 
  12.     IFNULL L1  //對CharArray判空 
  13.     BIPUSH 10 
  14.     INVOKESTATIC kotlin/collections/ArraysKt.getOrNull ([CI)Ljava/lang/Character
  15.     DUP 
  16.     IFNULL L1  //對Char判空 
  17.     INVOKEVIRTUAL java/lang/Object.hashCode ()I 
  18.     INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer
  19.     GOTO L2 
  20.    L1 
  21.     POP 
  22.     ACONST_NULL 
  23.    L2 
  24.     INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V 
  25.    L3 
  26.     LINENUMBER 12 L3 
  27.     RETURN 
  28.    L4 
  29.     LOCALVARIABLE string Ljava/lang/String; L0 L4 0 
  30.     MAXSTACK = 3 
  31.     MAXLOCALS = 1 

由字節(jié)碼分析可見,其實所謂的 空指針安全操作符其實內(nèi)部就是以此判空來確保不出現(xiàn)空指針 ,如果字節(jié)碼不好理解,那我們使用上面的Decompile功能,將bytecode轉(zhuǎn)成Java,如圖操作

研究學(xué)習(xí)Kotlin的一些方法

反編譯后得到的Java代碼為

 

  1. public static final void testNullSafeOperator(@Nullable String string) { 
  2.       PrintStream var10000; 
  3.       Integer var5; 
  4.       label18: { 
  5.          var10000 = System.out
  6.          if(string != null) { 
  7.             PrintStream var2 = var10000; 
  8.             if(string == null) { 
  9.                throw new TypeCastException("null cannot be cast to non-null type java.lang.String"); 
  10.             } 
  11.  
  12.             char[] var4 = ((String)string).toCharArray(); 
  13.             Intrinsics.checkExpressionValueIsNotNull(var4, "(this as java.lang.String).toCharArray()"); 
  14.             char[] var3 = var4; 
  15.             var10000 = var2; 
  16.             if(var3 != null) { 
  17.                Character var10001 = ArraysKt.getOrNull(var3, 10); 
  18.                if(var10001 != null) { 
  19.                   var5 = Integer.valueOf(var10001.hashCode()); 
  20.                   break label18; 
  21.                } 
  22.             } 
  23.          } 
  24.  
  25.          var5 = null
  26.       } 
  27.  
  28.       var10000.println(var5); 
  29.    } 

這樣讀起來是不是更加容易理解呢。

Object類型研究

這里我們回到Object類型,還是再舉個例子看看如何使用

 

  1. //這是定義 
  2. object AppSettings { 
  3.     fun updateConfig() { 
  4.         //do some updating work 
  5.     } 

關(guān)于應(yīng)用也很簡單

 

  1. //在Kotlin文件中調(diào)用 
  2. AppSettings.updateConfig() 
  3.  
  4. //在Java文件中調(diào)用 
  5. AppSettings.INSTANCE.updateConfig(); 

我們先看一下AppSettings的字節(jié)碼文件

 

  1. // ================AppSettings.class ================= 
  2. // class version 50.0 (50) 
  3. // access flags 0x31 
  4. public final class AppSettings { 
  5.   // access flags 0x11 
  6.   public final updateConfig()V 
  7.    L0 
  8.     LINENUMBER 7 L0 
  9.     RETURN 
  10.    L1 
  11.     LOCALVARIABLE this LAppSettings; L0 L1 0 
  12.     MAXSTACK = 0 
  13.     MAXLOCALS = 1 
  14.  
  15.   // access flags 0x2 
  16.   private <init>()V 
  17.    L0 
  18.     LINENUMBER 4 L0 
  19.     ALOAD 0 
  20.     INVOKESPECIAL java/lang/Object.<init> ()V 
  21.     ALOAD 0 
  22.     CHECKCAST AppSettings 
  23.     PUTSTATIC AppSettings.INSTANCE : LAppSettings; 
  24.     RETURN 
  25.    L1 
  26.     LOCALVARIABLE this LAppSettings; L0 L1 0 
  27.     MAXSTACK = 1 
  28.     MAXLOCALS = 1 
  29.  
  30.   // access flags 0x19 
  31.   public final static LAppSettings; INSTANCE 
  32.  
  33.   // access flags 0x8 
  34.   static <clinit>()V 
  35.    L0 
  36.     LINENUMBER 4 L0 
  37.     //靜態(tài)代碼塊中實例化,即類加載時便開始實例化 
  38.     NEW AppSettings 
  39.     INVOKESPECIAL AppSettings.<init> ()V 
  40.     RETURN 
  41.     MAXSTACK = 1 
  42.     MAXLOCALS = 0 
  43.  
  44.   @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"}) 
  45.   // compiled from: AppSettings.kt 

由此可見,Kotlin的object也就是Java的單例模式的實現(xiàn),在靜態(tài)代碼塊初始化實例。如果字節(jié)碼沒有看懂的話,可以嘗試反編譯成Java代碼來詳細研究。

Lambda表達式研究

除此之外,Kotlin也是支持了Lambda表達式的。由于并非所有的JVM版本都支持invokedynamic(Lambda表達式依賴的字節(jié)碼指令),比如Java 6的JVM,這其中就包含了許多安卓設(shè)備。所以我們懷疑Kotlin可能是像Scala那樣將lambda表達式轉(zhuǎn)換成了匿名內(nèi)部類。

一個簡單的Lambda表達式例子

 

  1. class Test { 
  2.     fun testObservable() { 
  3.         val observable = Observable() 
  4.         observable.addObserver { o, arg -> 
  5.             System.out.println("$o $arg"
  6.         } 
  7.     } 

我們使用插件同樣查看bytecode

 

  1. // ================Test.class ================= 
  2. // class version 50.0 (50) 
  3. // access flags 0x31 
  4. public final class Test {  
  5.   // access flags 0x11 
  6.   public final testObservable()V 
  7.    L0 
  8.     LINENUMBER 8 L0 
  9.     NEW java/util/Observable 
  10.     DUP 
  11.     INVOKESPECIAL java/util/Observable.<init> ()V 
  12.     ASTORE 1 
  13.    L1 
  14.     LINENUMBER 9 L1 
  15.     ALOAD 1 
  16.     GETSTATIC Test$testObservable$1.INSTANCE : LTest$testObservable$1;  //這里就是使用了匿名內(nèi)部類(常常包含$字符) 
  17.     CHECKCAST java/util/Observer 
  18.     INVOKEVIRTUAL java/util/Observable.addObserver (Ljava/util/Observer;)V 
  19.    L2 
  20.     LINENUMBER 12 L2 
  21.     RETURN 
  22.    L3 
  23.     LOCALVARIABLE observable Ljava/util/Observable; L1 L3 1 
  24.     LOCALVARIABLE this LTest; L0 L3 0 
  25.     MAXSTACK = 2 
  26.     MAXLOCALS = 2 
  27.  
  28.   // access flags 0x1 
  29.   public <init>()V 
  30.    L0 
  31.     LINENUMBER 6 L0 
  32.     ALOAD 0 
  33.     INVOKESPECIAL java/lang/Object.<init> ()V 
  34.     RETURN 
  35.    L1 
  36.     LOCALVARIABLE this LTest; L0 L1 0 
  37.     MAXSTACK = 1 
  38.     MAXLOCALS = 1 
  39.  
  40.   @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"}) 
  41.   // access flags 0x18 
  42.   final static INNERCLASS Test$testObservable$1 null null 
  43.   // compiled fromSpace.kt 
  44.  
  45.  
  46. // ================Test$testObservable$1.class ================= 
  47. // class version 50.0 (50) 
  48. // access flags 0x30 
  49. //生成的匿名內(nèi)部類,規(guī)則為  當(dāng)前的類名$當(dāng)前的方法名$匿名內(nèi)部類序號 
  50. final class Test$testObservable$1 implements java/util/Observer  {  
  51.   // access flags 0x11 
  52.   public final update(Ljava/util/Observable;Ljava/lang/Object;)V 
  53.    L0 
  54.     LINENUMBER 10 L0 
  55.     GETSTATIC java/lang/System.out : Ljava/io/PrintStream; 
  56.     NEW java/lang/StringBuilder 
  57.     DUP 
  58.     INVOKESPECIAL java/lang/StringBuilder.<init> ()V 
  59.     ALOAD 1 
  60.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder; 
  61.     LDC " " 
  62.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; 
  63.     ALOAD 2 
  64.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder; 
  65.     INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; 
  66.     INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V 
  67.    L1 
  68.     LINENUMBER 11 L1 
  69.     RETURN 
  70.    L2 
  71.     LOCALVARIABLE this LTest$testObservable$1; L0 L2 0 
  72.     LOCALVARIABLE o Ljava/util/Observable; L0 L2 1 
  73.     LOCALVARIABLE arg Ljava/lang/Object; L0 L2 2 
  74.     MAXSTACK = 3 
  75.     MAXLOCALS = 3  
  76.   // access flags 0x0 
  77.   <init>()V 
  78.     ALOAD 0 
  79.     INVOKESPECIAL java/lang/Object.<init> ()V 
  80.     RETURN 
  81.     MAXSTACK = 1 
  82.     MAXLOCALS = 1  
  83.   // access flags 0x19 
  84.   public final static LTest$testObservable$1; INSTANCE 
  85.  
  86.   // access flags 0x8 
  87.   static <clinit>()V 
  88.     NEW Test$testObservable$1 
  89.     DUP 
  90.     INVOKESPECIAL Test$testObservable$1.<init> ()V 
  91.     PUTSTATIC Test$testObservable$1.INSTANCE : LTest$testObservable$1; 
  92.     RETURN 
  93.     MAXSTACK = 2 
  94.     MAXLOCALS = 0  
  95.   @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"}) 
  96.   OUTERCLASS Test testObservable ()V 
  97.   // access flags 0x18 
  98.   final static INNERCLASS Test$testObservable$1 null null 
  99.   // compiled fromSpace.kt 

分析字節(jié)碼可以看到有兩個class文件,因此可以推斷出Kotlin的Lambda表達式目前是一種基于內(nèi)部類的語法糖實現(xiàn)。

除此之外,我們還可以使用kotlinc(Kotlin編譯器來驗證)

  1. kotlinc Test.kt 

執(zhí)行完成后,查看生成的class文件

 

  1. ls | grep ^Test 
  2. Test$testObservable$1.class 
  3. Test.class 
  4. Test.kt 

當(dāng)然,我們還可以使用javap同樣實現(xiàn)查看bytecode的功能,即 javap -c className 。

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

  • lazy初始化
  • when表達式
  • 方法引用

關(guān)于Kotlin的研究方法目前就是這些,Kotlin很簡單,但也要知其所以然,方能游刃有余編碼。希望大家可以嘗試Kotlin,并玩的開心。

責(zé)任編輯:未麗燕 來源: 技術(shù)小黑屋
相關(guān)推薦

2010-05-19 14:12:49

IIS FTP

2010-01-20 15:12:45

C++語言

2009-06-23 15:52:55

J2EE學(xué)習(xí)開源項目

2011-04-18 17:28:58

J2EE

2017-10-23 12:22:58

Android編程基礎(chǔ)總結(jié)

2009-06-18 13:42:48

Hibernate s

2009-12-24 17:01:42

ADO3.0

2023-09-04 16:55:18

2021-04-19 17:25:08

Kubernetes組件網(wǎng)絡(luò)

2013-12-24 14:50:39

Ember.js框架

2012-06-15 09:41:40

Linux內(nèi)核

2017-02-21 13:36:11

iosAPP性能

2020-02-03 09:09:23

機器學(xué)習(xí)ML深度學(xué)習(xí)

2013-03-18 10:24:50

系統(tǒng)架構(gòu)

2009-09-04 13:11:25

ASP.NET生成XM

2021-10-26 13:55:53

搞定系統(tǒng)設(shè)計

2009-08-27 10:06:15

Scala的構(gòu)造方法

2020-12-04 09:11:45

Python加密文件爆破字典

2010-05-12 17:45:01

IIS 服務(wù)器

2009-11-30 13:40:43

VS 2003 Boo
點贊
收藏

51CTO技術(shù)棧公眾號