Kotlin文法記事のトップレベル関数、中置呼び出し、および脱構築宣言について話す(4)

https://blog.csdn.net/suyimin2010/article/details/89415287
https://my.oschina.net/u/3847608/blog/1837612
簡単な説明: 今日はKotlinトークシリーズの4番目の弾丸です。今回は主に、JavaにはないKotlinのユニークな新機能について説明します。Kotlinは多くの新機能を追加する言語であり、より簡潔で読みやすいコードを記述できるため、コードの保守が容易になります。たとえば、最上位の関数とプロパティを使用すると、Javaでの静的、中置式の呼び出し、および分解宣言が不要になります。

  • 1.Javaの静的関数を置き換えるためにトップレベル関数を使用する理由
  • 2.トップレベルの関数と属性の基本的な使用
  • 3.トップレベル機能の基本原則
  • 4.トップレベルの関数を使用するときに注意すべき問題
  • 5.インフィックスコールシンタックスシュガーを試してみましょう
  • 6.インフィックスコールの基本的な使用法
  • 7.インフィックスコールの基本原則
  • 8.インフィックスを呼び出すときに注意すべき問題
  • 9.Kotlinでの脱構築ステートメント

1.Javaの静的関数を置き換えるためにトップレベル関数を使用する理由

概念:  Javaには静的関数と静的プロパティがあることがわかっています。それらの一般的な目的は、グローバルな共有アクセス領域とメソッドを提供することです。私たちの一般的な記述習慣は、静的に変更されたメソッドをラップするクラスを記述し、外部アクセスにクラス名とメソッド名を直接使用することです。

質問: 静的関数には、いわゆる純粋関数である状態が含まれていないことは誰もが知っています。その入力はパラメーターリストからのみ取得され、出力はパラメーターリストのみに依存します。このような開発シナリオを想像してみましょう。インスタンスオブジェクトを使用して関数を呼び出したくない場合があるため、通常は静的関数を静的関数コンテナクラスに追加します。この方法を繰り返すと、間違いなくこのクラスコンテナが膨らみます。

解決策:  Kotlinでは、関数またはメソッドがどのクラスにも属していない場合があり、独立して存在できます。したがって、Kotlinの同様の静的関数と静的プロパティは外部クラスのコンテナを削除します。関数またはプロパティはKotlinファイルのトップレベルで直接定義できます。関数またはプロパティをインポートする必要があるのは、それが使用されている場所だけです。コードに「Util」サフィックスで終わるユーティリティクラスがまだたくさんある場合は、それらを削除します。

第二に、トップレベルの関数と属性の基本的な使用法

Koltinでは、静的関数をラップする意味がないコンテナクラスを定義する必要はありません。これらはすべて、トップレベルのファイルに置き換えられます。Kotlinファイルを定義し、その中にいくつかの関数を定義するだけで済みます(注:staticキーワードは必要ありません)。次に、これらの関数を静的関数として使用できます

トップレベルファイルを作成します。

 

トップレベルファイルで関数を定義します。

package com.mikyou.kotlin.top
 
import java.math.BigDecimal
 
/**
 * Created by mikyou on 2018/4/10.
 */
//这个顶层函数不属于任何一个类,不需要类容器,不需要static关键字
fun formateFileSize(size: Double): String {
    if (size < 0) {
        return "0 KB"
    }
 
    val kBSize = size / 1024
    if (kBSize < 1) {
        return "$size B"
    }
 
    val mBSize = kBSize / 1024
    if (mBSize < 1) {
        return "${BigDecimal(kBSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} KB"
    }
 
    val mGSize = mBSize / 1024
    if (mGSize < 1) {
        return "${BigDecimal(mBSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} MB"
    }
 
    val mTSize = mGSize / 1024
    if (mTSize < 1) {
        return "${BigDecimal(mGSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} GB"
    }
    return "${BigDecimal(mTSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} TB"
}
 
//测试顶层函数,实际上Kotlin中main函数和Java不一样,它可以不存在任何类容器中,可以直接定义在一个Kotlin 文件中
//另一方面也解释了Kotlin中的main函数不需要了static关键字,实际上它自己就是个顶层函数。
fun main(args: Array<String>) {
    println("文件大小: ${formateFileSize(15582.0)}")
}

上記のコードから、トップレベル関数を定義するのは非常に簡単であることがわかります。問題は、formateFileSize関数をファイルでどのように定義するか、JVMでどのように実行するかです。読んでください...

第三に、トップレベル機能の本質的な原則

上記の例を通して、JVMでトップレベル関数がどのように実行されるかを考えてみましょう。Kotlinでこれらのトップレベル関数のみを使用する場合は、詳細に立ち入る必要はありません。ただし、JavaとKotlinの混合開発モデルの場合は、内部原則を深く掘り下げる必要があります。KotlinとJavaは相互運用性が高いことは誰もが知っているので、疑問が生じます。Kotlinで定義された最上位の関数をJavaで呼び出すことはできますか?答えは間違いなくイエスです。電話のかけ方は、引き続きご覧ください。

内部呼び出しの原則が非常に単純であることを知るには、上記のサンプルコードを一目でJavaコードに逆コンパイルするだけで済みます。これは、Kotlinコードを逆コンパイルするための一般的な科学的ステップです。これは、Kotlinの構文糖衣構文の背後にある本質を確認するための良い方法だからです。

ステップ1:  KotlinプラグインがIDEにインストールされていることを確認します

 

ステップ2:  IDEで逆コンパイルされたコードを表示するために必要なコードファイルを開き、上部にある[ツール]を開き、[Kotlin]を選択してから、[Show KotlinByteCode]を選択します

ステップ3:  Kotlinのソースコードは左側にあり、KotlinのByteCodeは右側にあります

ステップ4: 右側の「逆コンパイル」をクリックします

package com.mikyou.kotlin.top;
 
import java.math.BigDecimal;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
 
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 2,
   d1 = {"\u0000\u001c\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0006\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\b\u0002\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0003\u001a\u0019\u0010\u0004\u001a\u00020\u00052\f\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\u00010\u0007¢\u0006\u0002\u0010\b¨\u0006\t"},
   d2 = {"formateFileSize", "", "size", "", "main", "", "args", "", "([Ljava/lang/String;)V", "production sources for module Function"}
)
public final class TopExtFileFormatKt {//一般以文件名+"Kt"后缀作为容器类名
   @NotNull
   public static final String formateFileSize(double size) {//顶层函数反编译成Java中静态函数
      if(size < (double)0) {
         return "0 KB";
      } else {
         double kBSize = size / (double)1024;
         if(kBSize < (double)1) {
            return "" + size + " B";
         } else {
            double mBSize = kBSize / (double)1024;
            if(mBSize < (double)1) {
               return "" + (new BigDecimal(String.valueOf(kBSize))).setScale(1, 4).toPlainString() + " KB";
            } else {
               double mGSize = mBSize / (double)1024;
               if(mGSize < (double)1) {
                  return "" + (new BigDecimal(String.valueOf(mBSize))).setScale(1, 4).toPlainString() + " MB";
               } else {
                  double mTSize = mGSize / (double)1024;
                  return mTSize < (double)1?"" + (new BigDecimal(String.valueOf(mGSize))).setScale(1, 4).toPlainString() + " GB":"" + (new BigDecimal(String.valueOf(mTSize))).setScale(1, 4).toPlainString() + " TB";
               }
            }
         }
      }
   }
 
   public static final void main(@NotNull String[] args) {//顶层函数反编译成Java中静态函数
      Intrinsics.checkParameterIsNotNull(args, "args");
      String var1 = "文件大小: " + formateFileSize(15582.0D);
      System.out.println(var1);
   }
}

上記のコードから2つのポイントを要約できます。

  • 1.最上位のファイルはコンテナクラスに逆コンパイルされます。(クラス名は通常、デフォルトで最上位のファイル名+「Kt」サフィックスになります。コンテナのクラス名はカスタマイズできることに注意してください)
  • 2.最上位関数は、formateFileSizeやコード内のメイン関数などの静的静的関数に逆コンパイルされます。

この時点で、JavaでKotlinのトップレベル関数を呼び出す方法を推測したと思います。呼び出しメソッドは非常に単純です。つまり、逆コンパイルによって生成されたクラスを静的関数コンテナークラスとして使用して、対応する関数を直接呼び出します。

package com.mikyou.kotlin.top;
 
/**
 * Created by mikyou on 2018/4/10.
 */
public class TopExtTest {
    public static void main(String[] args) {
        System.out.println("文件大小: " + TopExtFileFormatKt.formateFileSize(1343553));// Java中调用Kotlin中定义顶层函数,一般是顶层文件名+"Kt"后缀作为静态函数的类名调用相应函数
    }
}

4つ目は、トップレベルの関数を使用するときに注意が必要な問題です。

Kotlinのトップレベル関数が逆コンパイルされるJavaのコンテナクラス名は、通常、トップレベルのファイル名+クラス名としての「Kt」サフィックスですが、カスタマイズすることもできます。つまり、最上位のファイル名は、生成されたコンテナクラスの名前に必ずしも関連しているわけではありません。Kotlinの@file:JvmName( "カスタム生成クラス名")アノテーションを使用すると、対応するJava呼び出しクラス名を自動的に生成できます。パッケージ宣言の前にファイルの先頭に配置する必要があることに注意してください。

//通过@file: JvmName("FileFormatUtil")注解,将生成的类名修改为FileFormatUtil,并且调用的时候直接调用FileFormatUtil.formateFileSize()即可
//放在文件顶部,在package声明的前面
@file: JvmName("FileFormatUtil")
 
package com.mikyou.kotlin.top
 
import java.math.BigDecimal
 
/**
 * Created by mikyou on 2018/4/10.
 */
//这个顶层函数不属于任何一个类,不需要类容器,不需要static关键字
fun formateFileSize(size: Double): String {
    if (size < 0) {
        return "0 KB"
    }
 
    val kBSize = size / 1024
    if (kBSize < 1) {
        return "$size B"
    }
 
    val mBSize = kBSize / 1024
    if (mBSize < 1) {
        return "${BigDecimal(kBSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} KB"
    }
 
    val mGSize = mBSize / 1024
    if (mGSize < 1) {
        return "${BigDecimal(mBSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} MB"
    }
 
    val mTSize = mGSize / 1024
    if (mTSize < 1) {
        return "${BigDecimal(mGSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} GB"
    }
    return "${BigDecimal(mTSize.toString()).setScale(1, BigDecimal.ROUND_HALF_UP).toPlainString()} TB"
}
 
//测试顶层函数,实际上Kotlin中main函数和Java不一样,它可以不存在任何类容器中,可以直接定义在一个Kotlin 文件中
//另一方面也解释了Kotlin中的main函数不需要了static关键字,实际上它自己就是个顶层函数。
fun main(args: Array<String>) {
    println("文件大小: ${formateFileSize(15582.0)}")
}

次に、Javaコードに逆コンパイルするとどうなるかを見てみましょう。

package com.mikyou.kotlin.top;
 
import java.math.BigDecimal;
import kotlin.Metadata;
import kotlin.jvm.JvmName;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
 
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 2,
   d1 = {"\u0000\u001c\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0006\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\b\u0002\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0003\u001a\u0019\u0010\u0004\u001a\u00020\u00052\f\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\u00010\u0007¢\u0006\u0002\u0010\b¨\u0006\t"},
   d2 = {"formateFileSize", "", "size", "", "main", "", "args", "", "([Ljava/lang/String;)V", "production sources for module Function"}
)
@JvmName(//注意这里多了注解
   name = "FileFormatUtil"
)
public final class FileFormatUtil {//这里生成的类名就是注解中自定义生成的类名了
   @NotNull
   public static final String formateFileSize(double size) {
      if(size < (double)0) {
         return "0 KB";
      } else {
         double kBSize = size / (double)1024;
         if(kBSize < (double)1) {
            return "" + size + " B";
         } else {
            double mBSize = kBSize / (double)1024;
            if(mBSize < (double)1) {
               return "" + (new BigDecimal(String.valueOf(kBSize))).setScale(1, 4).toPlainString() + " KB";
            } else {
               double mGSize = mBSize / (double)1024;
               if(mGSize < (double)1) {
                  return "" + (new BigDecimal(String.valueOf(mBSize))).setScale(1, 4).toPlainString() + " MB";
               } else {
                  double mTSize = mGSize / (double)1024;
                  return mTSize < (double)1?"" + (new BigDecimal(String.valueOf(mGSize))).setScale(1, 4).toPlainString() + " GB":"" + (new BigDecimal(String.valueOf(mTSize))).setScale(1, 4).toPlainString() + " TB";
               }
            }
         }
      }
   }
 
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      String var1 = "文件大小: " + formateFileSize(15582.0D);
      System.out.println(var1);
   }
}

このように、Javaがカスタムクラス名のトップレベル関数を呼び出すのがより自然です。一般に、アノテーションを使用してクラス名を変更することをお勧めします。これにより、Javaレイヤーでの呼び出しが引き続き私たちが慣れているツールクラス。この関数がJavaで定義されているのかKotlinで定義されているのかを認識することは完全に不可能です。完全に透過的であるため。

package com.mikyou.kotlin.top;
 
/**
 * Created by mikyou on 2018/4/10.
 */
public class TopExtTest {
    public static void main(String[] args) {
        System.out.println("文件大小: " + FileFormatUtil.formateFileSize(1343553));// Java中调用Kotlin中定义顶层函数,如果自定义生成类名,直接用定义类名调用。
    }
}
5、一緒に中置呼び出しの構文糖衣構文を試してください

中置呼び出しは非常に高度な概念のようです。実際、原理は非常に単純ですが、文法レベルで大幅に簡略化され、より便利で理解しやすくなっています。自然言語に近いコードを記述しましょう。私は個人的に、中置呼び出しは実際には1つのパラメーターのみを持つ元の関数呼び出しを2つの操作に減らし、クラス名またはオブジェクト名+ "。" +関数名の呼び出しメソッドを省略して、同様の中置演算子を直接使用して呼び出すことを理解しています。ナンセンスな話をするのではなく、波のキャンディーを送るだけです

  • 例1:マップを初期化する
package com.mikyou.kotlin.infix
 
/**
 * Created by mikyou on 2018/4/10.
 */
//普通利用Pair()初始化一个map
fun main(args: Array<String>) {
    val map = mapOf(Pair(1, "A"), Pair(2, "B"), Pair(3, "C"))
    map.forEach { key, value ->
        println("key: $key   value:$value")
    }
}
 
//利用to函数初始化一个map
fun main(args: Array<String>) {
    val map = mapOf(1.to("A"), 2.to("B"), 3.to("C"))
    map.forEach { key, value ->
        println("key: $key   value:$value")
    }
}
 
//利用to函数中缀调用初始化一个map
fun main(args: Array<String>) {
    val map = mapOf(1 to "A", 2 to "B", 3 to "C")//to实际上一个返回Pair对象的函数,不是属于map结构内部的运算符,但是to在语法层面使用很像中缀运算符调用
    map.forEach { key, value ->
        println("key: $key   value:$value")
    }
}
  • 2つの文字列の比較の例
    //普通使用字符串对比调用StringUtils.equals(strA, strB)
    fun main(args: Array<String>) {
    	val strA = "A"
    	val strB = "B"
    	if (StringUtils.equals(strA, strB)) {//这里对比字符串是了apache中的StringUtils
    		println("str is the same")
    	} else {
    		println("str is the different")
    	}
    }
     
    //利用中缀调用sameAs对比两个字符串
    fun main(args: Array<String>) {
    	val strA = "A"
    	val strB = "B"
    	if (strA sameAs strB) {//中缀调用 sameAs
    		println("str is the same")
    	} else {
    		println("str is the different")
    	}
    }

     

  • 例3:要素がセットに含まれているかどうかを確認する
//普通调用集合contains方法判断元素是否在集合中
fun main(args: Array<String>) {
    val list = listOf(1, 3, 5, 7, 9)
    val element = 2
    if (list.contains(element)) {
        println("element: $element is into list")
    } else {
        println("element: $element is not into list")
    }
}
 
//利用中缀调用into判断元素是否在集合中
fun main(args: Array<String>) {
    val list = listOf(1, 3, 5, 7, 9)
    val element = 2
    if (element into list) {//中缀调用,这样的写法,会更加接近我们自然语言的表达,更容易理解
        println("element: $element is into list")
    } else {
        println("element: $element is not into list")
    }
}

6、中置呼び出しの基本的な使用法

中置呼び出しは非常に簡単に使用できます。正確には、同様の加算、減算、乗算、除算の演算子を使用します。呼び出し構造:A(関数名を挿入)B 例:要素をリストに追加

セブン、インフィックスコールの本質的な原則

7.1関数システムの組み込み中置呼び出し

  • ソースコード分析
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

 

分析:infixキーワードで変更された関数を使用して、2つのジェネリックオブジェクトAとB渡します。「A.to(B)」構造体は特殊な構造体です。一時的にレシーバー付きの構造体と呼ばれるため、次のようになります。 Aを参照し、関数のパラメーターは1つだけで、Pairオブジェクトを返します。これは、Aを参照し、それが着信Bタイプのオブジェクトです。

  • to関数はPairオブジェクトを作成し、それを破壊ステートメントで展開できます

注:中置呼び出しと分解宣言は2つの異なる概念であり、必要な関係はないことを説明します。中置呼び出しによって返されるオブジェクトは、分解宣言を使用して展開できるとしか言えず、分解はで同等です。展開図。たとえば、図のto関数はPair()オブジェクトを返し、Pairオブジェクトは非構造化宣言をサポートし、to関数は非構造化オブジェクトと等しいオブジェクトを返します。

 

7.2関数のカスタム中置呼び出し

  • ソースコード分析
infix fun <T> T.into(other: Collection<T>): Boolean = other.contains(this)

 

 

 

分析:汎用Tオブジェクト要素が汎用Tセットに存在するかどうかinfixキーワードで変更された関数。「T.into(Collection <T>)」構造体は、実際にはレシーバーを備えた構造体です。これは、into関数の前のT型オブジェクトの呼び出しを指します。

8.インフィックスを呼び出すときに注意すべき問題

  • 1. to、into、same上記のように、実際には関数呼び出しです。infixキーワードが削除された場合、それは純粋に関数呼び出しメソッドに従います。たとえば、1.to( "A")、element.into(list)などは、infixというキーワードinfixを追加した後でのみ、1から "A"、element intolistなどの単純なinfix呼び出しを使用できます。 。

  • 2.すべての関数を中置呼び出しとして記述できるわけではありません。中置呼び出しは、最初に関数パラメーターが1つしかないという条件を満たす必要があります。次に、この関数の参加者が2つの要素しかないかどうかを確認します。これらの2つの要素は、2つの数値、2つのオブジェクト、またはセットにすることができます。

ナイン、コトリンの脱構築ステートメント

9.1破壊宣言の概要

破壊宣言は、オブジェクトを個別の変数のセットとして扱うことです。オブジェクトを個別の変数のセットとして扱う方が簡単になる場合があります。注:分解宣言をサポートするオブジェクトのクラスは、データクラス(dataキーワードで変更されたクラス)である必要があります。これは、データクラスのみが対応するcomponent()メソッドを生成するためです(これについては後で説明します)。クラス各属性には、対応するcomponent()メソッドがあります

9.2脱構築ステートメントの基本的な使用法

  • 最初にデータクラスを定義します
package com.mikyou.kotlin.destruct
 
/**
 * Created by mikyou on 2018/4/10.
 */
data class Student(var name: String, var age: Int, var grade: Double)
  • 破壊宣言呼び出し
package com.mikyou.kotlin.destruct
 
/**
 * Created by mikyou on 2018/4/10.
 */
fun main(args: Array<String>) {
    val student = Student("mikyou", 18, 99.0)
    val (name, age, grade) = student//将一个student对象解构成一组3个单独的变量
    println("my name is $name , I'm $age years old, I get $grade score")//解构后的3个变量可以脱离对象,直接单独使用
 
}

9.3分解された宣言の本質的な原則

破壊宣言は、実際にはオブジェクト内のすべての属性を属性変数のセットに分解することであり、これらの変数は別々に使用できます。各属性値の取得は最終的に対応するコンポーネントにコンパイルされるため、なぜ別々に使用できるのですか( )メソッド、各component()メソッドは、クラス内の各属性の値に対応し、スコープ内の各属性のローカル変数を定義します。これらのローカル変数は、対応する各属性の値を格納するため、変数は次のことができるようです。実際には、ローカル変数が使用されます。次の逆コンパイルされたJavaコード

package com.mikyou.kotlin.destruct;
 
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
 
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 2,
   d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "production sources for module Function"}
)
public final class DestructTestKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      Student student = new Student("mikyou", 18, 99.0D);
      String name = student.component1();//对应的component1()方法,返回对应就是Student中name属性,并赋值给创建局部变量name
      int age = student.component2();//对应的component2()方法,返回对应就是Student中age属性, 并赋值给创建局部变量age
      double grade = student.component3();//对应的component3()方法,返回对应就是Student中属性,并赋值给创建局部变量grade
      String var6 = "my name is " + name + " , I'm " + age + " years old, I get " + grade + " score";
      System.out.println(var6);//注意: 这里单独使用的name, age, grade实际上是局部变量
   }
}

 

 

 

9.4ステートメントを分解するときに注意を払う必要がある問題

  • 1.分解宣言内の分解されたオブジェクトのプロパティはオプションです。つまり、オブジェクト内のすべてのプロパティを分解する必要はありません。つまり、分解する必要のあるプロパティを選択できます。アンダースコア「_」を使用して、分解する必要のない属性を省略したり、属性を書き換えずに無視したりできます。注:2つの機能は同じですが、最終的なcomponent()メソッドは異なります。アンダースコアはcompoent1()メソッドを占有します。年齢はcomponent2()から直接生成され、名前は直接書き込まれません。 ageはcomponent1()から始まります。メソッドは生成を開始します。例えば

アンダースコア_名前属性の例を無視する

package com.mikyou.kotlin.destruct
 
/**
 * Created by mikyou on 2018/4/10.
 */
fun main(args: Array<String>) {
    val student = Student("mikyou", 18, 99.0)
    val (_, age, grade) = student//下划线_ 忽略name属性
    println("I'm $age years old, I get $grade score")//解构后的3个变量可以脱离对象,直接单独使用
}
 
//下划线_ 忽略name属性 反编译后Java代码
package com.mikyou.kotlin.destruct;
 
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
 
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 2,
   d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "production sources for module Function"}
)
public final class DestructTestKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      Student student = new Student("mikyou", 18, 99.0D);
      int age = student.component2();//name会占用component1()方法,但是没有生成,所以age从component2()方法开始
      double grade = student.component3();
      String var5 = "I'm " + age + " years old, I get " + grade + " score";
      System.out.println(var5);
   }
}
name属性を直接書き込まない例
package com.mikyou.kotlin.destruct
 
/**
 * Created by mikyou on 2018/4/10.
 */
fun main(args: Array<String>) {
    val student = Student("mikyou", 18, 99.0)
    val (age, grade) = student//直接不写name属性
    println("I'm $age years old, I get $grade score")//解构后的3个变量可以脱离对象,直接单独使用
}
 
//直接不写name属性 反编译后Java代码
package com.mikyou.kotlin.destruct;
 
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
 
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 2,
   d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "production sources for module Function"}
)
public final class DestructTestKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      Student student = new Student("mikyou", 18, 99.0D);
      String age = student.component1();//直接不写name,然后age从component
      int grade = student.component2();
      String var4 = "I'm " + age + " years old, I get " + grade + " score";
      System.out.println(var4);
   }
}
  • 2.破壊宣言のオブジェクトタイプはデータクラスである必要があり、通常のクラスは対応するコンポーネントを生成しないメソッドです。

おすすめ

転載: blog.csdn.net/az44yao/article/details/112918101