? ワイルドカード型
- ## extends T> は型の上限を示し、パラメーター化された型が T または T のサブクラスである可能性があることを示します;
- super T> は型の下限 (Java Core ではスーパー型修飾と呼ばれます) を表し、パラメータ化された型がこの型のスーパー型 (親型) であることを Object まで示します。
上限 T のすべてのクラスのコレクション。定義した List を使用して T のサブクラスを配置できると考えるかもしれません。次に、次のコードを見てみましょう。 :
import java.util.LinkedList;
import java.util.List;
public class test {
public static void main(String[] args) {
List<? extends Father> list = new LinkedList<>();
list.add(new Son());
}
}
class Human{
}
class Father extends Human{
}
class Son extends Father{
}
class LeiFeng extends Father {
}
ログイン後にコピー
list.add(new Son()); この行はエラーを報告します: メソッド put(Son) はタイプ List
に対して未定義です
List extends Father> は、「Son から継承された任意の型を持つリスト」を意味し、コンパイラは List が保持する型を判断できないため、リストにオブジェクトを安全に追加できません。 null は任意の型を表すことができるため、null を追加できます。したがって、List の add メソッドは意味のある要素を追加できませんが、既存のサブタイプ List の割り当ては受け入れることができます。 これを実行してみてください: List<? extends Father> list = new LinkedList<Son>();
list.add(new Son());
ログイン後にコピー
Son 型を指定した場合でも、add メソッドを使用して Son オブジェクトを追加することはできません。 Father クラスと Father クラスのサブクラスを リストに追加できないのはなぜですか? それを分析してみましょう。 List extends Father> は、上限が Father であり、次の代入が正当であることを意味します List<? extends Father> list1 = new ArrayList<Father>();
List<? extends Father> list2 = new ArrayList<Son>();
List<? extends Father> list3 = new ArrayList<LeiFeng>();
ログイン後にコピー
If List extends Father> は、add メソッドをサポートします: list1 は Father と Father のすべてのサブクラスを追加できます; その理由は、コンパイラーはコンテナーがファーザーまたはその派生クラスであることのみを認識しており、認識していないためです。特定のタイプ。もしかして父さん?もしかして息子さん?もしかしたらレイフェン、シャオミン?後で代入に Father が使用されることをコンパイラーが認識すると、コレクション内のパラメーターの型は「Father」に限定されなくなります。代わりに、プレースホルダーでマークされています: CAP#1 は、ファーザーまたはファーザーのサブクラスをキャプチャしていることを示します。特定のクラスはわかりませんが、コードは CAP#1 です。次に、Son、LeiFeng、または Father コンパイラを挿入するかどうかは、この CAP#1 に一致するかどうかわからないため、許可されません。 ワイルドカード > と型パラメーターの違いは、コンパイラーにとって、すべての T が同じ型を表すことです。たとえば、次の汎用メソッドでは、3 つの T はすべて同じ型 (String または Integer) を参照しています。 public <T> List<T> fill(T... t);
ログイン後にコピー
しかし、ワイルドカード > にはそのような制約はありません。List> は単に、コレクション内に何かがあるが、それが何であるかわからないことを意味します。 つまり、ここでのエラーは、List extends Father> には何も入れられないということです。 List extends Father> list は追加できませんが、このフォームは依然として非常に便利です。add メソッドは使用できませんが、Season は初期化中にさまざまなタイプを指定できます。例: List<? extends Father> list1 = getFatherList();//getFatherList方法会返回一个Father的子类的list
ログイン後にコピー
さらに、親クラスまたはそのサブクラスの 1 つが List に格納されていることを確認したため、get メソッドを使用して値を直接取得できます: List<? extends Father> list1 = new ArrayList<>();
Father father = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Object object = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Human human = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Son son = (Son)list1.get(0);
ログイン後にコピー
下限< ;? super T> は格納には影響しませんが、取得は Object オブジェクトにのみ配置できます。下限は super で宣言され、パラメータ化された型が指定された型である可能性があることを示します。またはこのタイプの親タイプ (オブジェクトまで)。 //super只能添加Father和Father的子类,不能添加Father的父类,读取出来的东西只能存放在Object类里
List<? super Father> list = new ArrayList<>();
list.add(new Father());
list.add(new Human());//compile error
list.add(new Son());
Father person1 = list.get(0);//compile error
Son son = list.get(0);//compile error
Object object1 = list.get(0);
ログイン後にコピー
下限は要素の最小粒度の下限を指定するため、実際にはコンテナ要素の型制御が緩和されます。この要素はFatherの基底クラスであるため、Fatherよりも小さい粒度で格納できます。型安全性の理由から、Father オブジェクトまたはそのサブクラス (Son など) を追加できますが、コンパイラは List の内容が Father のどのスーパークラスであるかを認識しないため、特定のスーパークラスを追加することはできません。 . クラス (人間など)。 Object は Java クラスの最終的な祖先クラスであるため、これを読み取ると、コンパイラはその型を認識せずに Object オブジェクトのみを返すことができます。ただし、この場合、要素の型情報はすべて失われます。 PECS 原則最後に、PECS (Producer Extends Consumer Super) 原則とは何かを見てみましょう。これはすでによく理解されています:
# 頻繁に外部から読み込むコンテンツの場合は、上限拡張を使用するのが適しています。
以上がJava の extends T と super T とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。