Java ジェネリックスの共分散、反分散、拡張および超選択メソッド

PHPz
リリース: 2023-05-26 13:46:12
転載
1295 人が閲覧しました

共分散と反分散を理解するには、まず次のことを導入する必要があります。

リスコフ置換原理によれば、C が P のサブクラスである場合、P は C を置き換えることができます。つまり、 P p = new C();
C は P から継承し、 C

不変とは何か

F が不変の場合、 C

たとえば、リスコフ置換原則によれば、Integer は Number のサブクラスです。

Number number = new Integer(1);  //correct
ログイン後にコピー

ただし、このように書くとエラーが報告されます

List<Number> list = new ArrayList<Integer>(1);  //error
ログイン後にコピー

Number と Integer には Integer < Number という継承関係がありますが、Java ではジェネリックはデフォルトで変更されないため、変更することもできます。 List<Number> および List<Integer> と見なされます。継承関係はありません

共分散とは

F が共分散の場合, when C <= P, then F(C) <= F(P)

Java は、不変性を共分散に変換するための extends を提供します。次に例を示します。 ##

List<? extends Number> list = new ArrayList<Integer>(1);  //corrent
ログイン後にコピー
このとき、

List<? extends Number>

は、ArrayList<Integer>

? の親クラスとみなすことができます。 extend Number

Number の特定のサブクラスを表す型範囲として見ることができます配列はデフォルトで共変です

Number[] numbers = new Integer[3];
ログイン後にコピー

反変性とは

If F は反変です。C <= P の場合、F(C) >= F(P)

Java は、不変式を共変式の Change に変換するためのスーパーを提供します。 :

List<? super Number> list = new ArrayList<Object>(1);  //corrent
ログイン後にコピー
このとき、

List

は、ArrayList<Object>## の親クラスとみなすことができます。 #extends と super

まず、Collection.add の実装を見てみましょう:

public interface List<E> extends Collection<E> { boolean add(E e); }
ログイン後にコピー
次のコードはエラーを報告しますか?

? extends NumberInteger

List<? extends Number> list = new ArrayList<Integer>(); // correct
list.add(Integer.valueOf(1));  //error
ログイン後にコピー
と一致しません。まず、add メソッドが呼び出されるとき、汎用の E

自動的に

2 行目はエラーを報告します。これは、? extends Number

Integer## の親クラスではないことを意味します。 #。ここで、List<? extends Number>ArrayList<Integer> の親クラスであることを区別する必要があります。 ? extends Number は、Number の特定のサブクラスを表す、型範囲内の特定の型と見なすことができますが、それがどのサブクラスであるかは明確ではありません。Float または Short である可能性があります。 . 、または Integer のサブクラスである可能性があります (Integer は Final によって変更され、サブクラスを持つことはできません。これは単なる仮定の状況です)。上限は Number として決定されるだけで、下限は決定されません (## が存在する可能性があります)。 # ? extends Number

<

Integer)、したがって ? extends NumberInteger の親クラスではありません上記のコードを変更します。少し変更すると正しくなります:

List<? super Number> list = new ArrayList<Object>(); // correct
list.add(Integer.valueOf(1));  //correct
ログイン後にコピー

まず第一に、反転のため、

List は ## の親クラスです。 #ArrayList<Object>。1 行は正しいです。

2 行目: ? super NumberInteger の親クラスです。理由は次のとおりです:

? super Number

は特定の親クラスを表しますNumber の場合、 Serializable または Object の場合がありますが、どちらであっても、 Number の親クラスは Integer の親クラスでなければならないため、2 行目は次のようになります。これも正しいです Use extends それともスーパーですか? java.util.Collections (JDK1.7) の copy メソッドから答えが得られます:

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    int srcSize = src.size();
    if (srcSize > dest.size())
        throw new IndexOutOfBoundsException("Source does not fit in dest");

    if (srcSize < COPY_THRESHOLD ||
        (src instanceof RandomAccess && dest instanceof RandomAccess)) {
        for (int i=0; i<srcSize; i++)
            dest.set(i, src.get(i));
    } else {
        ListIterator<? super T> di=dest.listIterator();
        ListIterator<? extends T> si=src.listIterator();
        for (int i=0; i<srcSize; i++) {
            di.next();
            di.set(si.next());
        }
    }
}
ログイン後にコピー

ジェネリックから変換するには クラスがデータを取得する場合は extends; を使用します

    データをジェネリック クラスに書き込む場合は super;
  • fetch と write の両方が必要です。ワイルドカードは必要ありません (つまり、extends も super も使用されません)
  • private static <E> E getFirst(List<? extends E> list){
        return list.get(0);
    }
    
    private static <E> void setFirst(List<? super E> list, E firstElement){
        list.add(firstElement);
    }
    
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        setFirst(list, 1);
        Number number = getFirst(list);
    }
    ログイン後にコピー

    以上がJava ジェネリックスの共分散、反分散、拡張および超選択メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート