Kotlin学習(8)ジェネリック

ジェネリック医薬品は、「抽象型」です。タイプは、固定値INT、文字列、ブールハンが、変数T(T = INT、T =文字列、T =ブール値)ではありません

ジェネリッククラス、インタフェースと機能において

ジェネリッククラス、インタフェース、機能が再利用、型安全性、及び効率の利点を有します。

1.1汎用インタフェース
ここでは一例です:

 interface Generator<T> {              //类型参数放在接口名称后面
     operator fun next(): T            //接口函数中直接使用类型T
}

    //测试代码:
    fun testGenerator() {
        val gen = object : Generator<Int> {    //对象表达式
            override fun next(): Int {
                return Random().nextInt()
            }
        }
        println(gen.next())
    }

上記にを使用します对象表达式私たちは、使用objectジェネレーターの実装クラスを宣言するためのキーワードを、そしてラムダ式の次の()関数を実装しています。

地図キーと値を入力はまた、Javaに精通し、一般的なもので、知っているが容易であるべきです。
例えばmutableMapOfは、()変数地図をインスタンス化します:

val map = mutableMapOf<Int, String>(1 to "a", 2 to "b", 3 to "c")
>>>map
{1=a, 2=b, 3=c}
map.add("5", "e")
>>>报错

//因为Kotlin中有类型推断的功能,有些类型参数可以直接不写,所以mutableMapOf后面的参数类型可以不写
val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c")

1.2ジェネリッククラス
:次のように我々は、パラメータの型の直接のコンテナクラスを宣言

class Container<K, V>(var key: K, var value: V)

次のようにテストコードがあります:

//<K, V>被具体化为<Int, String>
val container = Container<Int, String>(1, "A")
println(container)    //输出: container = Container(key = 1, value = A)

1.3一般的な機能
の汎用インタフェースやジェネリッククラスでは、我々は、クラス名の後にあるとのインタフェースの名前は、一般的なパラメータを宣言します。
事実ことができるクラスまたはインタフェース機能に直接汎用パラメータで宣言されたパッケージ・レベルの関数で宣言され、または直接ジェネリックパラメータで。
メソッド名の前に追加される<T>と、引数を<T>

class GenericClass{
    fun <T> console(t: T) {      //类中的泛型函数
       println(t)
    }
}

interface GenericInterface {
    fun <T> console(t: T)          //接口中的泛型函数
}

fun <T : Comparable<T>> gt(x: T, y: T): Boolean{     //包中的泛型函数
    return x > y
}

2.は、上限

fun <T : Comparable<T>> gt(x: T, y: T): Boolean //T的类型上界是Comparable<T>

ここでT:Comparable、同等のは、型Tの上限を表し、
つまり、コンパイラに伝えるために、Tパラメータタイプは、クラス実装していることComparableインタフェースによって表されます。
でJavaがあります<T extend Comparable>

何の上限ステートメントには存在しない場合、それは、関数で使用される演算子を使用することができることを確認する必要があります。

fun <T> gt(x: T, y:T): Boolean{
    return x > y   //编译不通过
}

3.共変性と反変性

問題のシナリオで見てみましょう。まず、親子関係のモデル次のように存在します。

open class Food
open class Fruit : Food()    //Fruit继承Food
class Apple : Fruit()        //Apple继承Fruit
class Banana : Fruit()       //Banana继承Fruit
class Grape : Fruit()        //Grape继承Fruit

//两个函数
object GenericTypeDemo {
   fun addFruit(fruit: MutableList<Fruit>){}
   fun getFruit(fruit: MutableList<Fruit){}
}

今回は2つの機能の上に呼び出すことができます。

val fruits: MutableList<Fruit> = mutableListOf(Fruit(), Fruit(), Fruit())
GenericTypeDemo.addFruit(fruits)
GenericTypeDemo.getFruit(fruits)

今、私たちは店、Appleのリストを持っています:

val aples: MutableList<Apple> = mutableListOf(Apple(), Apple(), Apple())

Kotlinのジェネリック医薬品と共変など非Java以来​​。したがって、次の呼び出しがでコンパイルされていません。

GenericTypeDemo.addFruit(apples)
GenericTypeDemo.getFruit(apples)

何の共分散がない場合、我々は2行のコードでGenericTypeDempに追加する必要があります。

fun addApple(apple: MutableList<Apple>)
fun getApple(apple: MutableList<Apple>)

このような繰り返しのコードは望ましいものではありません。
Javaでは、私たちが使用<? extend T>上限は、使用して決定<? super T>下限を決定します。
ここでは、抽象型定義はスコープを持っていたに対応し、ワイルドカードタイプです。

Number(Fと略す)型は、親タイプの種類INTEGER(Cと略す)であり、我々は、C =>パンF(CがFを継承)、一方リスト<番号>、一覧<整数としてこの関係呼ば > 代表タイプタイプは©F、F(F)と略記され
、その後、我々は共変とインバータを記述することができます。

  • 場合C => F、F©=> F(F)場合、fが呼び出される共変
  • F(F)は> F©IF =ときCは=> Fは、その後、fは、インバータと呼ばれます。

上記2人の関係が確立されていない場合は、同じように呼ばれます。

3.1共変
Javaの配列では共変です。次のコードは、正しく実行することができます:

Integer[] ints = new Integer[3];
ints[0] = 0;
ints[1] = 1;
Number[] numbers = new Number[3];
numbers = ints;     //数组是协变的,所以可以正确赋值

Javaでは、整数番号は整数どこ必要番号[]の値[]値を提供することができ、したがって整数[]番号は、配列[]のサブクラスのサブクラスであり、。
ただし、変更の非汎用Java協会。Javaの一般的な非共変における従って共変の配列を以下のように:

ここに画像を挿入説明
配列に上記のコードは、エラーのリストが表示されます。
私たちは、ワイルドカードを使用する場合でも、エラーが書き込まれます。

List<? extends Number> list = new ArrayList<Number>();
list.add(new Integer(1))   //报错

なぜ数整数をインスタンス化することができますが、ArrayListには、<番号>のArrayList <Integer型>はワイルドカードが作業をしていない場合でも、インスタンス化されることはない。ここでは、質問があります。
この問題を解決するために、我々は、インバータと共変とジェネリック医薬品のワイルドカードの使用でJavaを理解する必要があります。

共分散は、リストの意味である<?> =>リスト<?拡張番号>

List<? extends Number> list1 = new ArrayList<Integer>();
List<? extends Number> list2 = new ArrayList<Float>();

//编译
list1.add(null);           //编译ok
list2.add(null);           //编译OK
list1.add(new Integer(1))  //编译错误
list2.add(new Float(1f))   //编译错误

一覧<整数>、リスト<フロート > すべてのリストは、サブタイプ<?ナンバーを拡張>です。
今の質問は、あなたがリストに追加フロートをサブクラス化することができれば、<?数が伸びる>、整数リストに追加サブクラス化することも可能です。<?数が伸びる>、その後、一覧は<?数が伸び>で開催されますオブジェクトの数の様々なサブタイプがあります。そして、この時間は、我々は再び、このリストを使用する場合、要素の種類は非常に混乱することができます。私たちは、整数である要素かわかりません。またはFLOAT。
Javaはその型の一貫性を保護するために、<?番号は拡張>オブジェクトがリストに番号の任意のサブタイプを禁止する追加します。しかし、あなたは空のオブジェクトはnullを追加することができます。

3.2インバータ
のは、コードの例のサブセクションを使用してみましょう:

List<? super Number> list = new ArrayList<Object>();

ここでは、サブタイプC「?スーパーナンバー」は、親の型の親は、Number型(オブジェクト)です。
次のようにコード例は以下のとおりです。

List<? super Number> list1 = new ArrayList<Number>();
List<? super Number> list2 = new ArrayList<Object>();

list1.add(new Integer(3));          //可以添加Integer类型的元素
list2.add(new Integer(4));          //ok

インバータ式では、我々はそれに要素を追加することができます。
あなたは<?スーパーナンバー>で一覧に番号とサブクラスのオブジェクトを追加することができます。

TでT与アウト4

でKotlinは放棄されたこのワイルドカード、消費者のオブジェクトの代わりにTにおけるプロデューサオブジェクトの代わりにTアウト投射型の導入。
これは心の中ですることができます:

  • Tは同等である外に?Tを拡張
  • T中に?スーパーTと同等です

型消去

KotlinとJavaは、実行時に、パラメータのこれらのタイプは消去されます。
ジェネリックは、コンパイラレベルで実装され、生成されたクラスのバイトコードは、ジェネリック型に含まれていません。
例えば、上記のコードリストの<Object>一覧<文字列>と他のタイプは、コンパイルリストの後になります。JVMは、唯一のリストを参照してください。

公開された248元の記事 ウォン称賛99 ビュー10万+

おすすめ

転載: blog.csdn.net/rikkatheworld/article/details/102983781