日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
研究學(xué)習(xí)Kotlin的一些方法

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

成都創(chuàng)新互聯(lián)服務(wù)項目包括富順網(wǎng)站建設(shè)、富順網(wǎng)站制作、富順網(wǎng)頁制作以及富順網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,富順網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到富順省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

普通的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 { 
  2. }

那么問題來了,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())
  3. }

當(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

  • 上面的步驟操作后,會得到這樣的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
  32. }

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

反編譯后得到的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.             char[] var4 = ((String)string).toCharArray();
  12.             Intrinsics.checkExpressionValueIsNotNull(var4, "(this as java.lang.String).toCharArray()");
  13.             char[] var3 = var4;
  14.             var10000 = var2;
  15.             if(var3 != null) {
  16.                Character var10001 = ArraysKt.getOrNull(var3, 10);
  17.                if(var10001 != null) {
  18.                   var5 = Integer.valueOf(var10001.hashCode());
  19.                   break label18;
  20.                }
  21.             }
  22.          }
  23.          var5 = null;
  24.       }
  25.       var10000.println(var5);
  26.    }

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

Object類型研究

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

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

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

 
 
 
 
  1. //在Kotlin文件中調(diào)用
  2. AppSettings.updateConfig()
  3. //在Java文件中調(diào)用
  4. 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.   // access flags 0x2
  15.   private ()V
  16.    L0
  17.     LINENUMBER 4 L0
  18.     ALOAD 0
  19.     INVOKESPECIAL java/lang/Object. ()V
  20.     ALOAD 0
  21.     CHECKCAST AppSettings
  22.     PUTSTATIC AppSettings.INSTANCE : LAppSettings;
  23.     RETURN
  24.    L1
  25.     LOCALVARIABLE this LAppSettings; L0 L1 0
  26.     MAXSTACK = 1
  27.     MAXLOCALS = 1
  28.   // access flags 0x19
  29.   public final static LAppSettings; INSTANCE
  30.   // access flags 0x8
  31.   static ()V
  32.    L0
  33.     LINENUMBER 4 L0
  34.     //靜態(tài)代碼塊中實例化,即類加載時便開始實例化
  35.     NEW AppSettings
  36.     INVOKESPECIAL AppSettings. ()V
  37.     RETURN
  38.     MAXSTACK = 1
  39.     MAXLOCALS = 0
  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\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"})
  41.   // compiled from: AppSettings.kt
  42. }

由此可見,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.     }
  8. }

我們使用插件同樣查看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. ()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.   // access flags 0x1
  28.   public ()V
  29.    L0
  30.     LINENUMBER 6 L0
  31.     ALOAD 0
  32.     INVOKESPECIAL java/lang/Object. ()V
  33.     RETURN
  34.    L1
  35.     LOCALVARIABLE this LTest; L0 L1 0
  36.     MAXSTACK = 1
  37.     MAXLOCALS = 1
  38.   @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"})
  39.   // access flags 0x18
  40.   final static INNERCLASS Test$testObservable$1 null null
  41.   // compiled from: Space.kt
  42. }
  43. // ================Test$testObservable$1.class =================
  44. // class version 50.0 (50)
  45. // access flags 0x30
  46. //生成的匿名內(nèi)部類,規(guī)則為  當(dāng)前的類名$當(dāng)前的方法名$匿名內(nèi)部類序號
  47. final class Test$testObservable$1 implements java/util/Observer  {
  48.   // access flags 0x11
  49.   public final update(Ljava/util/Observable;Ljava/lang/Object;)V
  50.    L0
  51.     LINENUMBER 10 L0
  52.     GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
  53.     NEW java/lang/StringBuilder
  54.     DUP
  55.     INVOKESPECIAL java/lang/StringBuilder. ()V
  56.     ALOAD 1
  57.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
  58.     LDC " "
  59.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
  60.     ALOAD 2
  61.     INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
  62.     INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
  63.     INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
  64.    L1
  65.     LINENUMBER 11 L1
  66.     RETURN
  67.    L2
  68.     LOCALVARIABLE this LTest$testObservable$1; L0 L2 0
  69.     LOCALVARIABLE o Ljava/util/Observable; L0 L2 1
  70.     LOCALVARIABLE arg Ljava/lang/Object; L0 L2 2
  71.     MAXSTACK = 3
  72.     MAXLOCALS = 3 
  73.   // access flags 0x0
  74.   ()V
  75.     ALOAD 0
  76.     INVOKESPECIAL java/lang/Object. ()V
  77.     RETURN
  78.     MAXSTACK = 1
  79.     MAXLOCALS = 1 
  80.   // access flags 0x19
  81.   public final static LTest$testObservable$1; INSTANCE
  82.   // access flags 0x8
  83.   static ()V
  84.     NEW Test$testObservable$1
  85.     DUP
  86.     INVOKESPECIAL Test$testObservable$1. ()V
  87.     PUTSTATIC Test$testObservable$1.INSTANCE : LTest$testObservable$1;
  88.     RETURN
  89.     MAXSTACK = 2
  90.     MAXLOCALS = 0 
  91.   @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={"", "", "o", "Ljava/util/Observable;", "kotlin.jvm.PlatformType", "arg", "", "update"})
  92.   OUTERCLASS Test testObservable ()V
  93.   // access flags 0x18
  94.   final static INNERCLASS Test$testObservable$1 null null
  95.   // compiled from: Space.kt
  96. }

分析字節(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,并玩的開心。


網(wǎng)頁名稱:研究學(xué)習(xí)Kotlin的一些方法
標(biāo)題URL:http://m.5511xx.com/article/cocsgcs.html