ホームページ  >  記事  >  Java  >  Java ジェネリックスの共分散、反分散、拡張および超選択メソッド

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

PHPz
PHPz転載
2023-05-26 13:46:121292ブラウズ

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

リスコフ置換原理によれば、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 b990d0161a5780c8b48560ac36663132 および Listc0f559cc8d56b43654fcbe4aa9df7b4a と見なされます。継承関係はありません

共分散とは

F が共分散の場合, when C

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

List<? extends Number> list = new ArrayList<Integer>(1);  //corrent
このとき、

Lista2b037db85f4e1df0e812b9647ac55a8

は、ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a

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

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

Number[] numbers = new Integer[3];

反変性とは

If F は反変です。C = F(P)

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

List<? super Number> list = new ArrayList<Object>(1);  //corrent
このとき、

Listda50108ad159903fabe211f1543600e8

は、ArrayLista87fdacec66f0909fc0757c19f2d2b1d## の親クラスとみなすことができます。 #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

自動的に

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

Integer## の親クラスではないことを意味します。 #。ここで、Lista2b037db85f4e1df0e812b9647ac55a8ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a の親クラスであることを区別する必要があります。 ? 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

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

Listda50108ad159903fabe211f1543600e8 は ## の親クラスです。 #ArrayLista87fdacec66f0909fc0757c19f2d2b1d。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 までご連絡ください。