kotlin の学習 (1) 基本概念、データ オブジェクトの種類、制御フロー、null 値の検査、クラスとインターフェイス

Kotlin について

ここに画像の説明を挿入
Java 言語と同様、kotlin はバイトコードにコンパイルされ、JVM 仮想マシンで実行されます。kotlin 言語の機能は、kotlin の構文コンパイラーに依存します。kotlinに似た言語は次のとおりです。

  • Scala: ビッグ データ ドメイン開発言語
  • Groovy: JVM プラットフォームに基づく動的スクリプト言語、Android 開発で依存関係やプラグインなどを記述するために使用されます。

2019 年、Google は Kotlin が Android の最初の開発言語になると発表し、Android プログラマーが Java から Kotlin に切り替える時期が差し迫っています。

クロスプラットフォーム機能

言語の種類

言語はインタープリタ言語とコンパイル言語に分けられます。

  • コンパイル言語。コンパイラはソース コードを一度に 1 つずつバイナリ ファイルにコンパイルし、コンピュータはそれを直接実行できます。C和C++
    • 利点: 一度コンパイルすれば実行でき、実行時にコンパイルは必要なく、効率が高くなります。
    • 欠点: オペレーティング システムが異なれば必要なマシン コードも異なり、コードを変更するにはモジュールごとに再コンパイルする必要があります。
  • インタープリター型言語。プログラムの実行中に、インタープリターはソース コードを 1 行ずつリアルタイムでバイナリに解析し、対応する仮想マシンで実行します。JS、Python
    • 利点: プラットフォームの互換性が高く、対応する仮想マシンをインストールした後に実行できます。
    • 短所: 実行時に解釈して実行する必要があり、効率が低い。

Java言語の種類

Java は正確には、半分コンパイルされ、半分解釈されたハイブリッド言語ですが、より解釈されます。

Java は、まずコンパイラ javac を通じてソース プログラムをプラットフォームに依存しない Java バイトコード (.class) にコンパイルし、次にそのバイトコードを JVM によって解釈して実行します。

kotlin の仕組み

JVM は、バイトコード ファイルの生成方法に関係なく、バイトコード file.class の解釈と実行のみを担当します。Kotlin はこの原則に基づいており、実行前にクラスにコンパイルされ、Java 仮想マシンによって実行されます。

Kotlin不仅能够,还能脱离虚拟机层,直接编译成可以在Windows、Linux和MacOS平台上运行的原生二进制代码,被称为Android领域的Swift

こんにちは世界

Kotlin アプリケーションのエントリ ポイントはメイン関数 main です。この関数はパラメータを取らず、値も返しません。

fun main() {
    
    
    var str:String = "Hello World"
    println(str)
}

基本的な考え方

プログラムエントリー

パラメーターまたはパラメーター リストがない場合もありますが、プログラム エントリには戻り値がありません。

fun main() {
    
    
}

fun main(args: Array<String>) {
    
    
}

データとオブジェクトのタイプ

kotlinでは、Java本来の基本的なデータ型は廃止され、すべてのオブジェクト型が使用されます。
ここに画像の説明を挿入
ここに画像の説明を挿入

== と ===

Kotlin はオブジェクトを比較する 2 つの方法を提供します

  • オブジェクトの構造が等しいかどうかを比較します (==またはequals)
  • オブジェクト参照が等しいかどうかを比較する===
fun main() {
    
    
//sampleStart
    val a: Int = 100
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    val b: Int = 10000
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b

    println(boxedA === anotherBoxedA) // true
    println(boxedB === anotherBoxedB) // false
//sampleEnd
}

JVM は -128 から 127 (整数) までの整数にメモリの最適化を適用するため、 へのすべての null 許容参照は実際には同じオブジェクトです。ただし、 b にはメモリ最適化が適用されないため、これらは別のオブジェクトになります (===結果は false)。

一方、それらの内容は依然として同等です。

fun main() {
    
    
//sampleStart
    val b: Int = 10000
    println(b == b) // 输出“true”
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b
    println(boxedB == anotherBoxedB) // 输出“true”
//sampleEnd
}

明示的な数値変換

Kotlin の小さい型を大きい型に暗黙的に変換することはできません。つまり、変数Byteへの型の割り当てはInt明示的に変換する必要があります。

fun main() {
    
    
	val b : Byte = 1

	val i1: Int = b.toInt();
}

すべての数値型は、他の型への変換をサポートしています。

  • toByte(): バイト
  • toShort(): ショート
  • toInt(): 整数
  • toLong(): 長い
  • toFloat(): 浮動小数点数
  • toDouble(): 倍精度

多くの場合、型はコンテキストから推論され、適切な変換を行うために算術演算がオーバーロードされるため、明示的な型変換は必要ありません。次に例を示します。

val l = 1L + 3 // Long + Int => Long

浮動小数点型

Kotlin は浮動小数点型の Float 型と Double 型を提供します。これらは異なるサイズを持ち、2 つの異なる精度の浮動小数点数のストレージを提供します。
ここに画像の説明を挿入

  1. 10 進数で初期化された変数の場合、コンパイラーはDouble型を推論します。
val pi = 3.14  // Double
// val one: Double = 1 // 错误:类型不匹配
val oneDouble = 1.0 //Double
  1. 値をFloat型として明示的に指定するには、追加fまたはF接尾辞を追加します。そのような値に 6 ~ 7 桁を超える 10 進数が含まれる場合、そのような値は四捨五入されます。
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float,实际值为 2.7182817
  1. 他の言語とは異なり、Kotlin の数値には暗黙的な拡大変換がありません。たとえば、Double パラメーターを持つ関数は Double 値に対してのみ呼び出すことができ、Float、Int、その他の数値に対しては呼び出すことができません。
fun main() {
    
    
    fun printDouble(d: Double) {
    
     print(d) }

    val i = 1    
    val d = 1.0
    val f = 1.0f 

    printDouble(d)
//    printDouble(i) // 错误:类型不匹配
//    printDouble(f) // 错误:类型不匹配
}

ビット演算

Kotlin は、整数型Intとに対するLong一連のビット単位の演算を提供します。

  • shl(bits) – 符号付き左シフト (左シフト)
  • shr(bits) – 符号付き右シフト (右シフト)
  • ushr(bits) – 符号なし右シフト
  • and(bits) – ビットと
  • or(bits) – ビットまたは
  • xor(bits) – ビット排他的論理和
  • inv() – ビット単位の逆変換

どれでも

Any は空ではない型のルート型であり、Java クラス階層の最上位レベルの Object に似ています。Any がAny类型是Kotlin中所有非空类型的超类。Kotlin 関数で使用されると、Java バイトコードの Object にコンパイルされます。

Any?类型是Kotlin所有类型的根类
Kotlin 型階層の最下位には Nothing 型があります。型構造図は次のとおりです。
ここに画像の説明を挿入

ユニット

Unit関数としてはJavaと似ていますvoidが、voidの意味は戻り値がないということです。Kotlinの方がオブジェクトとの向き合いが徹底されています。戻り値のない戻り値もオブジェクトであるはずなのでUnitがあります。この概念であれば、戻り値が
明示的に指定されていない場合return、コンパイラは自動的に return を追加しますUnit

fun returnUnit() : Unit {
    
    
	return Unit
}

何もない

Unitこの関数の意味は戻り値がありません。
ただしNothing、それはこの関数が返さないことを開発者に確認するなど可能是抛异常、返ってこない、または拥有无限循环的函数。

関数1: 例外をスローする関数の戻り値

fun throwOnNameNull() : Nothing {
    
    
	throw NullPointerException("姓名不能为空!")
}

上記の例外スローの使用に加えて、==Nothing オブジェクトはすべてのオブジェクト タイプの共通のサブタイプでもあります。==このように、Nothing は実際には多重継承です。つまり、継承ルールは Kotlin で拡張されます。Nothing类不允许多重继承,Nothing除外のコンストラクターはプライベートであり、インスタンス オブジェクトを持たないため、多重継承は実際のリスクを引き起こしません。 。

Nothing はすべての型のサブクラスであるという事実に基づいて、次のようにジェネリックと組み合わせてジェネリックな空のリストを構築できます。

ここに画像の説明を挿入
機能 2: 一般的な変数の一時的な空白埋めとして

機能 3: 文法レベルで kotlin をこれ以上に完全なものにするものはありません。

kotlin の基礎となるロジックでは、 throw には戻り値があり、その戻り値の型は Nothing である
ため、次の記述は正当です。

val nothing: Nothing = throw RuntimeException("抛异常!"

Nothing はすべての型のサブクラスであるため、次のすべてが機能します。

var _name: String? = null
val name: String = _name ?:throw NullPointerException("_name 运行时不能为空!")

変数を宣言する

Kotlin はキーワードを使用してvar可変変数を宣言し、変数名と変数の型は:コロンで区切られます。このスクリプト言語は、Python と同様、;末尾を必要としません。

ここに画像の説明を挿入
var: 変数変数。Java の非final 変数に対応します。

var b = 1

valfinal: Java変数に対応する不変変数

val a = 1

:上記の宣言処理では型を示すためにコロンを使用していません。Kotlin にはクラス導出機構があるため、代入結果に応じて上記のa合計bがデフォルトとみなされます。Int

読み取り専用変数 val と可変変数 var

  • var: 変更可能な変数を示します
  • val: 読み取り専用変数を示します

主に非決勝と決勝の違いです。

Kotlin バイトコードを表示する

ここに画像の説明を挿入

fun (メソッド/関数)

fun キーワードはメソッドの宣言に使用されます。
以下は 2 つの Int パラメータを受け取り、Int を返すメソッドです。

fun sum(a: Int, b: Int): Int {
    
    
	return a + b;
}

メソッド本体には、戻り値を推論できる式を指定できます。

fun sum (a: Int, b: Int) = a + b 

メソッドは戻り値を持たないか、意味のない値を返すことができます (ユニット)

fun printSum(a: Int, b:Int): Unit {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

このうち、Unit は無視することもできます。

fun printSum(a: Int, b:Int) {
    
    
	println("sum of $a and $b is ${
      
      a + b}")
}

関数パラメータのデフォルト値

Kotlin は、次のように使用されるデフォルト値を持つ関数をサポートしています。

fun main() {
    
    
	myPrint(1)
	myPrint(1, "lalala")
}

fun myPrint(value : Int, str : String = "hello") {
    
    
	println("num is $value, str is $str")
}

渡される最初のパラメータは Int 型である必要があるため、値をデフォルト値にしたい場合は保存されます。受信文字列タイプは一致しません:

fun main() {
    
    
    myPrint("zjm")//报错
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

Kotlin の関数パラメーター受け渡しは、Python と同じキーと値のペアのパラメーター受け渡しをサポートしているため、パラメーターの順序を変更できます。

fun main() {
    
    
    myPrint(str = "zjm") //正确调用
}

fun myPrint(value: Int = 100, str: String) {
    
    
    println("num is $value, str is $str")
}

クラス(クラス)

クラスの定義
クラスの属性は、次のように定義内またはクラス内に配置できます。

class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

var rectangle = Rectangle(5.0, 2.0)
println("The perimeter is ${
      
      rectangle.perimeter}")

kotlin バージョン 1.4.30 では、クラスの継承は:コロンで表されます。クラスはデフォルトで Final であるため、継承できません。クラスを継承可能にするには、openキーワードを使用してクラスの前に置きます。

open class Rectangle(var height: Double, var length: Double) {
    
    
	var perimeter = (height + length) * 2
}

$(文字列テンプレート)

$文字列テンプレート、トランスパイルされた文字列変数の定義に使用できます。
変数を直接使用するには$、式を使用するには、中括弧が必要です${}

以下に例を示します。

var a = 1
val S1 = "a is $a"
println(S1)
a = 2;
val S2 = "${
      
      S1.replace("is", "was")}, but now is $a"
println(S2)

結果:

a is 1
a was 1, but now is 2

制御フロー

if-else(条件式)

fun getMax(a: Int, b: Int): Int {
    
    
	if (a > b) {
    
    
		return a
	} else {
    
    
		return b
	}
}

上記の if は、三項演算子と同様に、式として記述することもできます。

fun getMax(a: Int, b: Int) = if (a > b) a else b

サイクル

のために

  1. inキーワードを使用する
  2. 添え字を使用する
val items = listof("apple", "banana", "kiwifruit")
for (item in items) {
    
    
	println(item)
}

for (index in item.indices) {
    
    
	println("item at $index is ${
      
      items[index]}")
}
// 闭区间打印[1, 3]
// 输出 1,2,3
for (i in 1..3) {
    
    
	println(i)
}
// 从7到0,降序,步长为2
// 输出 7,5,3,1
for (i in 7 downTo 0 step 2) {
    
    
	println(i)
}

for- inデフォルトの範囲はダブルクローズド範囲です。左クローズドと右オープンを使用したい場合は、キーワードを使用する必要があります。until

fun main() {
    
    
	for (i in 0 until 10) {
    
    
		
	}
}

その間

val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
    
    
    println("item at $index is ${
      
      items[index++]}")
}

結果:

item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

表現のとき

when 式は Java の swich case に少し似ています。

fun describe(obj: Any): String = 
	when (obj) {
    
    
		1 -> "One"
		"Hello" -> "Greeting"
		is Long -> "Long"
		!is String -> "Not a String"
		else -> "Unknown"
	}

異常な

例外クラス Throwable

Kotlin のすべての例外クラスはクラスを継承し、式をThrowable使用してthrow例外をスローします。

fun main() {
    
    
//sampleStart
    throw Exception("Hi There!")
//sampleEnd
}

try ... catch 式を使用して例外をキャッチします。

try {
    
    
    // 一些代码
} catch (e: SomeException) {
    
    
    // 处理程序
} finally {
    
    
    // 可选的 finally 块
}

catch ブロックは 0 個以上存在でき、最後にブロックを省略できます。ただし、少なくとも 1 つのキャッチと最終ブロックが必要です。

NULL値とNULL値チェック

null を指定できる変数の後には疑問符が必要です?
たとえば、以下のメソッドは Int または null を返します。

fun parseInt(str: String) : Int? {
    
    
	...
}

安全な通話オペレーター?.

この演算子を使用すると、null チェックとメソッド呼び出しを 1 つの操作に結合できます。例えば

s?.toUpperCase()

次の記述と同等です。

if (s!=null) {
    
    
	s.toUpperCase
} else {
    
    
	null
}

安全な呼び出しは、メソッドの呼び出しだけでなく、プロパティへのアクセスにも使用できます。

オブジェクト内に null 許容型のプロパティが複数ある場合、同じ式で複数の安全な呼び出しを使用すると便利なことがよくあります。この演算子を使用すると、追加のチェックを行わずに、1 行のコードでより詳細なプロパティにアクセスできます。次のように:

class Address(val streetAddress:String,val code:Int,val city:String)
class Company(val name:String,val address: Address?)
class Person(val name:String,val company: Company?)

fun Person.cityName():String{
    
    
    val city = this.company?.address?.city
    return if (city != null) city else "unKnown"
}

エルヴィスのオペレーター?:

Elvis 演算子は 2 つのオペランドを受け取り、最初のオペランドが null でない場合、演算の結果は最初のオペランドになり、それ以外の場合、演算の結果は 2 番目のオペランドになります。
たとえば、以下では、s が空でない場合、str は s、それ以外の場合、str は空の文字列オブジェクトです。

fun foo(s: String) {
    
    
	val str: String = s?:""
}

Elvis 演算子は、null オブジェクトのメソッドを呼び出して返された null を値に置き換えるために、safe call 演算子とともによく使用されます。前のコードを単純化してみましょう。

fun Person.cityName():String {
    
    
	val city = this.company?.address?.city
	return city ?: "unKnown"
}

kotlin には Elvis オペレーターが非常に適しているシーンがありますが、return や throw などの操作は実際には式なので、Elvis オペレーターの右側に記述することができます。演算子の左側の値が null の場合、関数はすぐに例外をスローします。

fun printPersonName(person : Person) {
    
    
	val name = person.name? : throw IllegalArgumetException("no name")
	println(name)
}

変換に従ってくださいas?

これは、変換される値が変換しようとしている型ではない場合に、Java 型と同様に型を変換するために使用される Kotlin 演算子です。ClassCastException がスローされます。

as?演算子は値を指定された型に変換しようとします。値が適切な型でない場合は null を返します我々はできるエルヴィスでこの演算子を使用しますパーソンクラスのequalsメソッドの実装など

class Person(val name:String, val company: Company?) {
    
    
	override fun equals(other: Any?): Boolean {
    
    
		val otherPerson = other as? Person ?: return false
		return otherPerson.name && other.company == company
	}
}

非nullアサーション!!

非 null アサーションは、null 許容型の値を処理するために kotlin が提供する最もシンプルで直接的なツールです。二重感嘆符を使用して、任意の値を非 null 型に変換できることを示します。null に対して非 null アサーションが行われた場合、例外がスローされます。

fun ignoreNull(s:String){
    
    
    val notNull = s!!
    println(notNull.length)
}

この関数で s が null の場合、実行時に例外がスローされます。例外がスローされる場所は、値が使用される行ではなく、not-null アサーションが行われる行です。

例外コールスタックトレースの情報は、どの行で例外が発生したかだけを示すため、トレース情報をより明確にするには、末尾の同じ行に複数の!!アサーションを含めないでください。

機能させてください

let 関数を使用すると、null 許容式の操作が容易になります。安全な呼び出し演算子と組み合わせて使用​​すると、式の評価、結果が null かどうかの確認、結果の変数への格納をすべて同じ操作で行うことができます。シンプルな表現。

let 関数の機能は、それを呼び出すオブジェクトをラムダ式のパラメータに変換することです。安全な呼び出し構文と組み合わせることで、let 関数を呼び出す null 許容オブジェクトを非 null 型に効果的に変換できます。 、安全に呼び出すことができる let は、式が null でない場合にのみラムダを実行します。

s?.let {
    
     
    print(s.length)
}

上記の効果を実現したい場合、Java コードは次のようになります。

public static final void ignoreNull(@Nullable String s) {
    
    
	if (s != null) {
    
    
		System.out.print(s.length());
	}
}

lateinit 遅延初期化プロパティ

Kotlin では通常、すべてのプロパティがコンストラクターで初期化される必要があります。プロパティが null 以外のプロパティの場合は、null 以外の初期化値を指定する必要があり、それ以外の場合は null 許容型を使用する必要があります。これが行われる場合、プロパティは need またはassert します。null检查アクセスされるたびに!!

class MyService {
    
    
	fun performAction():String = "foo"
}

class MyTest{
    
    
	private var myService:MyService?=null
	
	fun test() {
    
    
		myService!!.performAction()
	}
}

myService の初期化を遅延するために使用できますlateinit。遅延初期化のプロパティはすべて var です。非 null 型ですが、コンストラクターで初期化する必要はありません。

class MyService{
    
    
    fun performAction():String = "foo"
}

class MyTest{
    
    
    // 声明一个不需要初始化器的非空类型的属性
    private lateinit var myService:MyService

    fun test(){
    
    
        myService.performAction()
    }
}

Null 許容型の拡張

Kotlin 標準ライブラリは、 String の 2 つの拡張関数を定義しisEmptyisBlank
isNullOrBlankそれが空の文字列であるかどうか、または空白文字のみが含まれているかどうかを判断します。この拡張関数を使用すると、レシーバーを null として呼び出すことができます。

fun  verifyInput(input:String?){
    
    
    if (input.isNullOrBlank()){
    
    
        print("it is not ok")
    }
}

可能性のある null 値は関数によって内部的に処理されるため、安全なアクセスは必要ありません。

@kotlin.internal.InlineOnly
public inline fun CharSequence?.isNullOrBlank(): Boolean {
    
    
    contract {
    
    
        returns(false) implies (this@isNullOrBlank != null)
    }

    return this == null || this.isBlank()
}

型パラメータの null 許容性

Kotlin のすべてのジェネリック クラスとジェネリック関数の型パラメーターは、デフォルトで null 可能です。この場合、型パラメーター T が疑問符で終わっていなくても、型パラメーターを型として使用する宣言では null が許可されます。

fun <T> printSomething(t:T){
    
    
    // 因为 t 可能为 null,所以必须使用安全调用
    print(t?.hashCode())
}
// 传入 null 进行调用
printSomething(null)

このメソッドでは、型パラメーター T の推定型は null 許容型 Any? であるため、実際のパラメーター t は、疑問符で終わっていなくても null を許可します。

型パラメーターが null 以外の場合は、ジェネリックスが実際のパラメーターとして null 許容値を拒否するように、null 以外の上限を指定する必要があります。

// 这样的话,T 就不是可空的
fun <T:Any> printSomething1(t:T){
    
    
    print(t.hashCode())
}

は: 型チェックと自動変換

isオブジェクトが特定の型であるかどうかを確認するために使用されます

fun getStringLength(obj: Any): Int? {
    
    
	if (obj is String) {
    
    
		// 这里obj已经转为String类型
		return obj.length
	}
	return null
}

または、!is逆に書くと次​​のようになります。

fun getStringLength(obj: Any): Int? {
    
    
	if (obj !is String) return null

	return obj.length
}

クラスとオブジェクト

人物クラスを作成します。

class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

継承する

Kotlin のデフォルト クラスは継承可能ではありません (つまり、final によって変更されます)。このクラスを継承したい場合はclassopenその前にキーワードを使用する必要があります。

open class Person {
    
    
	var name = ""
	var age = 0
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

Person クラスから継承する Student クラスを宣言します。kotlin では、継承には:親クラスの構造が使用されます。

class Student : Person() {
    
    
	var number = ""
	var grade = 0
	fun study() {
    
    
		println("$name is studying")
	}
}

構造

構造は主構造と二次構造に分かれています

主な構造

主要な構造はクラスの直後に書かれます

class Student(val number: String, val grade: Int) : Person() {
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

Student オブジェクトを作成します。

val student = Student("1234", 90)

親クラス person にも name 属性と age 属性があるため、親クラス person に対してメイン構造も構築されます。

open class Person(val name : String, val age : Int) {
    
    
	fun printInfo() {
    
    
		println("name is $name, age is $age")
	}
}

この時点で、Student はエラーを報告します。これは、Person を継承するときに、引数なしの Person() 構造が後で使用されるためです。また、上記では Person の引数なし構造を変更しているため、引数なし構造は存在しません。

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){
    
    
	fun study() {
    
    
		println("$name is studying")
	}
}

この時点で Student クラスを構築します。

val student = Student("zjm", 20, "1234", 90)

建設に特別な処理が必要な場合はどうすればよいですか? Kotlin はinit構造を提供し、次のようなメイン構造のロジックを init で処理できます。

open class Person(val name : String, val age : Int) {
    
    
	init {
    
    
		println("name is $name")
		println("age is $age")
	}
}

上記の変更はすべてです主构造が、クラスに複数の構成要素が必要な場合はどうすればよいでしょうか? 現時点では助けが必要です次构造

二次構造

二次構築では、constructorキーワードを使用してコンストラクターを宣言し、:その後にthis()を続けます。セカンダリ コンストラクターの本質は、プライマリ コンストラクターを呼び出すことです。
次の 2 つのサブ構造を実装します。

  1. 名前、年齢、番号、学年の 3 つのパラメータの構築ではパラメータは渡されません。デフォルトは 0 です。
  2. パラメータ構築なし: Int のデフォルトは 0、String のデフォルトは空の文字列
class Student(name: String,  age: Int, var number: String, var grade: Int) : Person(name, age){
    
    
    fun study() {
    
    
        println("$name is studying")
    }
    constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
    
    

    }
    
    constructor() : this("", 0, "", 0) {
    
    
        
    }
}

// 调用
val student = Student("lzy", 23, "1234", 90)
val student1 = Student("lzy", 23, "121");
val student2 = Student()

権限修飾子

Java と kotlin の違いは次のとおりです。
ここに画像の説明を挿入
kotlin 導入internal、廃止default

データ クラスとシングルトン クラス

データクラス

データ クラスは、、 、およびその他のメソッドJava Beanと同様のデータ関連のみを扱い、通常はこれらのメソッドを実装する必要があります。getsethashcodeequaltoString

次の実装には、 、属性がUserBean含まれますジャバ:idnamepwd

public class UserBean {
    
    
    private String id;
    private String name;
    private String pwd;

    public UserBean() {
    
    

    }

    public UserBean(String id, String name, String pwd) {
    
    
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserBean userBean = (UserBean) o;
        return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(id, name, pwd);
    }

    @Override
    public String toString() {
    
    
        return "UserBean{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getPwd() {
    
    
        return pwd;
    }

    public void setPwd(String pwd) {
    
    
        this.pwd = pwd;
    }
}

このクラスを Kotlin で書くと非常に簡単になり、新しいktファイルを作成して次のように選択すると、
ここに画像の説明を挿入
1 行のコードで実行でき、kotlin が上記のメソッドを自動的に実装します。
Shift をダブルクリックして を呼び出し工具搜索、検索しshow kotlin ByteCode、kotlin バイトコードを表示します。
対応する Java Bean クラスが実際に作成されます。
ここに画像の説明を挿入

シングルトンクラス

現在、Java で最も広く使用されているシングルトン モード (静的内部クラス) は次のように実装されます。

public class SingleInstance {
    
    
	private SingleInstance() {
    
    
	}
	private static class SingleHolder {
    
    
		private static final SingleInstance INSTANCE = new SingleInstance();
	}

	public static SingleInstance getInstance() {
    
    
		return SingleHolder.INSTANCE;
	}
	public void test() {
    
    
	}
}

Kotlinでシングルトン クラスを作成するには、Object
ここに画像の説明を挿入
次のように生成されたコードを選択する必要があります。

object SingleInstance {
    
    
	fun test () {
    
    
	}
}

対応するjavaファイルは次のとおりで、上記で最もよく使用されるjavaシングルトン実装と同様です。

public final class Singleton {
    
    
   @NotNull
   public static final Singleton INSTANCE;

   public final void test() {
    
    
   }

   private Singleton() {
    
    
   }

   static {
    
    
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

次のように使用します。

fun main() {
    
    
    Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}

列挙型クラス

列挙型クラスの最も基本的なアプリケーション シナリオは、タイプ セーフな列挙型を実装することです。

enum class Direction {
    
    
    NORTH, SOUTH, WEST, EAST
}

各列挙定数はオブジェクトです。列挙定数はカンマで区切られます。

すべての列挙は列挙クラスのインスタンスであるため、次のように初期化できます。

enum class Color(val rgb: Int) {
    
    
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

すべての列挙定数には、列挙クラス宣言内でその名前と位置 (0 から) を取得するために、名前と序数という 2 つのプロパティもあります。

enum class RGB {
    
     RED, GREEN, BLUE }

fun main() {
    
    
    //sampleStart
    println(RGB.RED.name) // prints RED
    println(RGB.RED.ordinal) // prints 0
    //sampleEnd
}

シールされたクラス シールされた

Result インターフェイスを定義します。

interface Result 
class Success(val msg: String) : Result
class Failure(val msg: String) : Result

メソッドを定義します。

fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
    else -> throw IllegalArgumentException()
}

Kotlin の性質上、else を記述する必要がありますが、上記のコードは 2 つの場合にのみ可能であり、else は純粋に冗長です。プログラマが UnKown クラスを渡すことを怠ると、APP がクラッシュします。

上記の問題を解決するには、sealedsealed クラスに依存する必要があり、そのサブクラスは同じファイルの最上位でのみ定義でき、他のクラスにネストすることはできません。

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
fun getResultMsg(result: Result) = when(result) {
    
    
    is Success -> result.msg
    is Failure -> result.error.message
}

インターフェース

インターフェースを定義します。

interface Study {
    
    
    fun study()
    fun readBooks()
    fun doHomeWork()
    fun exercise()
}

インターフェースの継承

継承されたインターフェイスはクラスの背後で使用し,Study宣言されたすべての関数を実装するだけで済みます。

class GoodStudent(name: String, age: Int, var ID: String, var grade: Int) : Person(name, age) , Study{
    
    
    override fun study() {
    
    
        TODO("Not yet implemented")
    }

    override fun readBooks() {
    
    
        TODO("Not yet implemented")
    }

    override fun doHomeWork() {
    
    
        TODO("Not yet implemented")
    }

    override fun exercise() {
    
    
        TODO("Not yet implemented")
    }

}

Kotlin はインターフェイス メソッドのデフォルト実装をサポートしており、JDK1.8 以降でもこの機能がサポートされており、メソッドにデフォルト実装がある場合、継承されたクラスはこのメソッドを実装する必要はありません。

interface Study {
    
    
    fun study() {
    
    
        println("study")
    }
    fun readBooks()
    fun doHomework()
}

オーバーレイの競合を解決する

複数のインターフェイスを実装する場合、同じメソッドの複数の実装を継承するという問題が発生する可能性があります。

interface A {
    
    
    fun foo() {
    
     print("A") }
    fun bar()
}

interface B {
    
    
    fun foo() {
    
     print("B") }
    fun bar() {
    
     print("bar") }
}

class C : A {
    
    
    override fun bar() {
    
     print("bar") }
}

class D : A, B {
    
    
    override fun foo() {
    
    
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
    
    
        super<B>.bar()
    }
}

上記の例では、インターフェイス A と B は両方ともメソッド foo() と bar() を定義しています。どちらも foo() を実装していますが、B のみ bar() を実装しています (bar() は、インターフェイスにメソッド本体がない場合にデフォルトで抽象となるため、A では抽象としてマークされていません)。ここで、A の具象クラス C を実装する場合は、bar() をオーバーライドして、この抽象メソッドを実装する必要があります。

ただし、A と B から D を派生する場合は、複数のインターフェイスから継承したすべてのメソッドを実装し、D がそれらを実装する方法を示す必要があります。このルールは、単一の実装を継承するメソッド ( bar() ) と複数の実装を継承するメソッド ( foo() ) の両方に適用されます。

機能インターフェイス (SAM) インターフェイス

抽象メソッドが 1 つだけあるインターフェイスは、関数インターフェイスまたは単一抽象メソッド (SAM) インターフェイスと呼ばれます。関数型インターフェイスには複数の非抽象メンバーを含めることができますが、抽象メンバーは 1 つだけです。

たとえば、次の Kotlin 関数インターフェイスがあります。

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

SAM 変換を使用しない場合は、次のようなコードを記述する必要があります。

// 创建一个类的实例
val isEven = object : IntPredicate {
    
    
   override fun accept(i: Int): Boolean {
    
    
       return i % 2 == 0
   }
}

Kotlin の SAM 変換を利用することで、代わりに次の同等のコードを変更できます。

fun interface IntPredicate {
    
    
   fun accept(i: Int): Boolean
}

val isEven = IntPredicate {
    
     it % 2 == 0 }

fun main() {
    
    
   println("Is 7 even? - ${
      
      isEven.accept(7)}")
}

おすすめ

転載: blog.csdn.net/baiduwaimai/article/details/131101935