Javaのコア技術の第8章 - ジェネリック

概要

よる「Javaコア・テクノロジー巻」の本の第八章からまとめ、記事の一部に個人的なメモとして、本を抜粋。
記事は、あまりにも深く、希望の読者は、良い参考になりません。

なぜジェネリックプログラミングを使用します

汎用プログラミング(ジェネリックプログラミング)コード書かれた手段は、オブジェクトの多くの異なる種類によって再利用することができます。

パラメータの利点タイプ

ジェネリッククラスが存在しない場合には、唯一のオブジェクト参照の配列を維持するために、ArrayListクラス:

public class ArrayList {
   private Object[] elementData; // 用于存放数据
   public Object get(int i) { . . . }
   public void add(Object o) { . . . }
     ...
}

問題

でなければならないキャストは値1を取得します
。2.エラーチェックがありませんが。配列の型と一致しないが、必須必須、エラーの結果が得られます場合は、任意の型のオブジェクトの配列にリストを追加することができます。

typeパラメータ:ジェネリックはより良いソリューションを提供します。

ArrayList<String> array = new ArrayList<String>():

データを追加する際に型パラメータの使用については、我々はそれが型を定義し、初期化する場合、コンパイラは、戻り値の型を特定するため、getメソッドは、キャストする時間を必要としない呼び出し、団結の種類を維持することができますタイプを変換する私たちを助けます。

シンプルな汎用的なクラスを定義します

public class Pair<T> {
    private T num;

    public Pair(T num) { this.num = num; }
    public T getNum() { return num; }
    public void setNum(T num) { this.num = num; }
}

私たちは、クラス名の後ろにペアを追加したことがわかります これは、次のような一般的なクラス型の変数でなく、変数の型が複数あり、

public class Pair<T,U> {
    ...
}

私たちはペアのクラスをインスタンス化した場合、例えば:

new Pair<String>;

次のようにその後、我々は、上述したペアのクラスを考えることができます。

public class Pair<String> {
    private String num;

    public Pair(String num) { this.num = num; }
    public String getNum() { return num; }
    public void setNum(String num) { this.num = num; }
}

それは単純ではないですか?Javaライブラリでは、変数Eを使用して要素型のセットを表し、K及びVは、それぞれのタイプのキーワードと値表を表し、T、Uは、Sは任意の型を表します。

一般的な方法

この方法は、タイプのパラメータで定義されています

    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }

あなたは、変数の型(<T>)バック修飾子(パブリック静的)で、戻り値の型(T)上記を見ることができます。一般的な方法は、一般的なクラスや通常のクラスで定義することができます。

変数の型を定義します

我々のような変数の種類に制約する必要がある場合:渡す変数変数法がのcompareToのニーズを呼び出すため、Comparableインタフェースを実装する必要があります。だから私たちが使用できるextends変数を定義するキーワードを。

    public <T extends Comparable> T max(T a) {
        a.compareTo(...);
        ...
    }

定義された変数は、クラスまたは実装インタフェースを継承する必要があるかどうか、あなたが使用しているextendsキーワードの制限を。

一般的なコードと仮想マシン

型消去

我々は、一般的なクラス、コードで定義されているかの一般的な方法を持っているかどうか、それは、対応するプリミティブ型を提供します。元の型の名前を削除すると、ジェネリッククラスの型パラメータの名前です。<T>元の型Object<T extends MyClass>元のタイプMyClass
このようなコード:

public class Pair<T> {
    private T property;

    public Pair(T property) {
        this.property = property;
    }
}

型消去後:

public class Pair<Object> {
    private Object property;

    public Pair(Object property) {
        this.property = property;
    }
}

翻訳一般的な表現

あなたは戻り値の型、次のようなコンパイラ挿入のキャストを、消去した場合:

Pair<Employee> buddies = . .
Employee buddy = buddies.getFirst();

消去getFirstとのObject型の戻り値の型後の復帰が、コンパイラが自動的に私たちは、従業員にキャストするのに役立ちます。
だから、このメソッドの動作を実行するために、コンパイラが2つの命令に分割されています。

元のメソッドの呼び出しPair.getFirst
Employee型へのオブジェクト戻り値の型キャスト

セクションの概要:

いいえ、一般的な仮想マシンのない、唯一のクラスとメソッドの一般的な
パラメータのすべてのタイプには、そのタイプに交換されている定義されている
必要が挿入キャスト場合、保持型の安全性と
ブリッジ開催された合成方法は、本明細書中で言及されていない(ポリモーフィックですしかし、ブリッジ法を無視することができ、Javaは)非標準法ブリッジの生成を記述する必要があります

制限事項

基本的なタイプの例は、パラメータの種類を使用することはできません

8つの基本データ型は、型パラメータをインスタンス化するために使用することはできません、あなたが見ていないArrayList<int>、このようなAコードにそれを。のみArrayList<Integer>基本的なデータ型がオブジェクトではないためです。そこで、彼らは唯一の包装の種類に置き換えることができます。

ファイル名を指定して実行時の型のクエリは元の型に適用されます

クエリのすべての種類は、仮想マシンにジェネリック型として理由なもの、唯一のプリミティブ型を生じませんでした。
例えば:

    Pair<String> pair = new Pair<String>("johnson");
    if (pair instanceof Pair<String>) {} // Error
    if (pair instanceof Pair<T>) {} // Error
    if (pair instanceof Pair) {} // Pass

あなたは、パラメータ化された型の配列を作成することはできません

    Pair<String>[] pairs = new Pair<String>[10]; //error

なぜ、この定義をすることはできませんか?そのためpairsのタイプでPair[]、それは変換することができObject[]ますが、他のタイプのエレメントを保存しようとした場合、例外は、ArrayStoreExceptionがスローされます

    pairs[0] = 10L; //抛异常

一言で、厳密ではありません。あなたは、配列のパラメータ化された型を作成することはできません。

Type変数インスタンス化することはできません

新しいT(...)、新しいT使用することはできません [...] またはT.classを。型消去するので、Tは、オブジェクトとなり、我々は確かにインスタンス化オブジェクトにしたいされていません。
しかしJava8の後、我々は使用することができるSupplier<T>パラメータを表し、関数Tのない戻り値の型が存在しない機能的なインターフェイスであるインターフェイスを、:

public class Pair<T> {
    private T first;
    private T second;

    private Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public static <T> Pair<T> makePair(Supplier<T> constr) {
        return new Pair<>(constr.get(), constr.get());
    }
    
    public static void main(String[] args) {
        Pair<String> pair = Pair.makePair(String::new);
    }
}

ジェネリッククラス型変数の静的コンテキストが無効です。

あなたは、型変数のドメインまたは静的メソッドでは参照できません。例えば:

public class Pair<T> {
    private static T instance; //Error

    public static T getInstance() { //Error
        if (instance == null) 
            instance = new Pair<T>();
        return instance;
    }
}

クラス型変数があるため(<T>)、オブジェクトの有効範囲、代わりの範囲内で有効なクラスがあります。あなたは一般的な方法を使用している場合は、記事では、上記を参照することが一般的な方法はああ〜

ジェネリッククラスのインスタンスを投げるか、キャプチャしません

オブジェクトは、ジェネリッククラスをキャプチャすることはできません投げることができない、でもThrowableのは違法である拡張します。

public class Pair<String> extend Exceotion {} //Error
public static <T extends Throwable> void doWork(Class<T> t) {
    try {
        ...
    } catch (T e) { //Error
        ...
    }
}

しかし、変数の型の使用を許可する例外に例外をスローした後(個人的な感情は、このようなAのコードを見たことがありません)。

public static <T extends Throwable> void doWork(Class<T> t) throw T { //Pass
    try {
        ...
    } catch (Exception e) {
        throw e;
    }
}

継承ルールの一般的なタイプ

このようなManagerクラスの継承Employeeクラス。しかし、Pair<Employee>Pair<Manager>関連付けられていません。次のコードのように、エラー、配信の失敗を促すメッセージが表示されます:

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<Employee> employeePair = managerPair; //Error

ワイルドカードタイプ

ワイルドカードのコンセプト

使用した変化型パラメータを可能にワイルドカードタイプ、?識別ワイルドカードタイプ:

Pair<? extends Employee>

ペアは次のようにクラスがある場合

public class Pair<T> {
    private T object;

    public void setObject(T object) {
        this.object = object;
    }
}

次に、あなたが解決するためにワイルドカードを使用でき後継のルールの一般的なタイプの次のような問題を、

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<? extends Employee> employeePair = managerPair; //Pass
        Manager manager = new Manager();
        employeePair.setObject(manager); //Error

使用すると、<?従業員が伸びる>、コンパイラは唯一employeePairは、従業員のサブクラスであることを知っているが、どのような特定のサブカテゴリー、最終的なステップは不明であるemployeePair.setObject(manager)実行することはできません。

ワイルドカードの定義スーパータイプ

ワイルドカードを使用すると、指定されてもよい、追加的な能力を持っているスーパー定義の型を次のような、

public class Pair<T> [
    ...
    public static void salary(Pair<? super Manager> result) {
        //...
    }
}

<? super Manager>例えば(マネージャを含む)の超マネージャー、すべてのタイプのためのワイルドカード:

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<Employee> employeePair = new Pair<Employee>();

        Pair.salary(managerPair); //Pass
        Pair.salary(employeePair); //Pass

        // 假如 ManagerChild为Manager子类
        Pair<ManagerChild> managerChildPair = new Pair<ManagerChild>();
        Pair.salary(managerChildPair); //Error

無期限のワイルドカード

次のような無期限のワイルドカード、Pair<?>我々はあなたがコードに、ワイルドカード不定を使用することができたときに彼の実際の型を気にする必要がない場合:

    public static boolean hasNull(Pair<?> pair) {
        return pair.getObject() == null;
    }

正直に言うと、それは何度も何度も記事を参照して、私のめまいワイルドカード行われ、ゆっくりと私はあまりにもハードだったことを理解し始めました。


記事はここに、小さなパートナーも見てとることができます改善するために私の記事の執筆のスキルや能力かもしれ言葉を理解していなかった、あなたは小さなパートナーを読んでいないかわからない、最後に来て、「Javaコアテクノロジーボリュームを」これをそれを予約し、気持ちがとても良いです。最近、また基盤は非常に重要な、最初沈殿した良いの基盤であり、その後、他の技術的なポイントを学ぶことから始めるのが容易になることが判明したビューのこの本のポイントを取り上げ、これらのコースを知っている知っています。最近非常に多くの言葉のように、彼は私たちを与えた:「小さなドングリから、ではない流砂知名度の高い建物で樫の。」

個人ブログのURL:https://colablog.cn/

あなたに私の記事が助けた場合、私は公共のマイクロチャネル番号、あなたの記事を共有するための最初の時間に集中することができます

マイクロチャンネル公衆数

おすすめ

転載: www.cnblogs.com/Johnson-lin/p/11981994.html