ホームページ  >  記事  >  Java  >  Java の汎用ワイルドカードと有界型パラメータ

Java の汎用ワイルドカードと有界型パラメータ

php是最好的语言
php是最好的语言オリジナル
2018-08-06 16:55:421449ブラウズ

型ワイルドカード

型ワイルドカードは通常、特定の型の実パラメータの代わりに ? を使用します (ここでは型仮パラメータではなく、型実パラメータを使用します)。型を操作するときにその型の特定の関数を使用する必要がなく、Object クラスの関数のみを使用する場合は、ワイルドカード文字 ? を使用して不明な型を表すことができます。たとえば、List6b3d0130bba23ae47fe2b8e8cddf0195 は、論理的には、Listf7e83be87db5cd2d9a8a0b8117b38cd4、Listc0f559cc8d56b43654fcbe4aa9df7b4a などのすべての List8e4a42b25090f2d9d55ce057d46e5cc5 の親クラスです。

public class GenericTest {    
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();   
        name.add("zwj");
        age.add(18);
        number.add(120);
   
        getNumberData(age); // 报错
        getNumberData(number); // 120
        getData(name);  // zwj
        getData(age); // 18
        getData(number); // 120
        //getUperNumber(name); // 出现错误,方法中的参数已经限定了参数泛型上限为Number
        getUperNumber(age); //18
        getUperNumber(number); //120       
    }
    /**
     * 在使用List<Number>作为形参的方法中,不能使用List<Ingeter>的实例传入,
     * 也就是说不能把List<Integer>看作为List<Number>的子类;
     */
    public static void getNumberData(List<Number> data) {
        System.out.println("data :" + data.get(0));
    }
    /**
     * 使用类型通配符可以表示同时是List<Integer>和List<Number>的引用类型。
     * 类型通配符一般是使用?代替具体的类型实参,注意此处是类型实参;
     * 和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。
     */
    public static void getData(List<?> data) {
        System.out.println("data :" + data.get(0));
    }
    /**
     * 类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
     */
    public static void getUperNumber(List<? extends Number> data) {
          System.out.println("data :" + data.get(0));
    }
}

境界付き型パラメーター

場合によっては、型パラメーターに渡すことができる型の範囲を制限したいことがあります。たとえば、数値を操作するメソッドは、Number のインスタンスまたは Number のサブクラスのみを受け入れたい場合があります。この時点で、Monkey はジェネリックに上限を追加する必要があります。つまり、渡される型引数は、指定された型のサブタイプでなければなりません。

境界付き型パラメーターを宣言するには、まず型パラメーターの名前をリストし、次に extends または super キーワード、最後にその上限または下限を続けます。このことから、ジェネリックの上限と下限の追加はジェネリックの宣言と同時に行う必要があることがわかります。

d203bb1ae585225d4838a2b7e3d0503e は、ワイルドカードで表される型が T 型のサブクラスであることを示します。 たとえば、コレクションに要素を追加する場合、E タイプ オブジェクトまたは E のサブタイプ オブジェクトを追加できます。なぜ?フェッチするときに、E タイプは E クラス オブジェクトと E サブタイプ オブジェクトの両方を受け取ることができるためです。

117c5a0bdb71ea9a9d0c2b99b03abe3e は、ワイルドカードで表される型が型 T の親クラスであることを意味します。たとえば、操作のためにコレクションから要素を取得する場合、現在の要素の型を使用してそれを受け取ることも、現在の要素の親の型を使用してそれを受け取ることもできます。

public class GenericMethodTest {
    // 比较三个值并返回最大值
    public static <T extends Comparable<T>> T getMaxNuum(T x, T y, T z) {                     
        T max = x; // 假设x是初始最大值
        if ( y.compareTo( max ) > 0 ){
            max = y; //y 更大
        }
        if ( z.compareTo( max ) > 0 ){
            max = z; // 现在 z 更大           
        }
        return max; // 返回最大对象
    }
    public static void main( String args[] ) {
        System.out.println( "结果 " + getMaxNuum(3, 4, 5) );  // 结果 5
        System.out.println( "结果 " + getMaxNuum(1.2, 6.6, 10.10) ); // 结果 10.10
   }
}

ジェネリック クラスの以前の定義を変更することもできます:

public class GenericClassDemo<T extends Number> { 
    private T t;   
    public GenericClassDemo() { 
    }
    public GenericClassDemo(T t) { 
        this.t = t;
    }
    public void setT(T t) {
        this.t = t;
    }
    public T getT(){ 
        return t;
    }
}

現時点では、GenericClassDemo ジェネリック クラスをインスタンス化するとき、パラメーターの型は Number と Number サブクラスのみにすることができます。これに基づいて、ジェネリック メソッドの例を見てみましょう:

/**
 * 在泛型方法中添加上下边界限制的时候, 必须在泛型声明的时候添加;
 * 也就是在权限修饰符与返回值之间的<T>上添加上下边界
 */
public <T extends Number> T getT(GeneriClassDemo<T> demo){
    T t = demo.getT();
    return t;
}

ジェネリック配列

Java では、正確なジェネリック型の配列を作成することはできません。

List<String>[] lsa = new ArrayList<String>[10];  // Not really allowed. 
Object o = lsa;    
Object[] oa = (Object[]) o;    
List<Integer> li = new ArrayList<Integer>();    
li.add(new Integer(3));    
oa[1] = li; // Unsound, but passes run time store check    
String s = lsa[1].get(0); // Run-time error: ClassCastException.

この場合、JVM の汎用消去メカニズムにより、JVM は実行時に汎用情報を知らないため、例外なく oa[1] に ArrayList を割り当てることができますが、データをフェッチするときに型変換が行われると、必須の場合、ClassCastException が発生します。ジェネリック配列を宣言できる場合、コンパイル中に警告やエラーは発生せず、エラーは実行時にのみ発生します。ジェネリック配列の宣言を制限すると、そのような場合、コードに型安全性の問題があることをコンパイル時に確認することができます。これは、プロンプトをまったく表示しないよりもはるかに優れています。

次のワイルドカード メソッドが許可されます: ワイルドカード メソッドが使用されない限り、配列の型を型変数にすることはできません。これは、ワイルドカード メソッドの場合、最後にデータを抽出するために明示的な型変換が必要であるためです。

List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.    
Object o = lsa;    
Object[] oa = (Object[]) o;    
List<Integer> li = new ArrayList<Integer>();    
li.add(new Integer(3));    
oa[1] = li; // Correct.    
Integer i = (Integer) lsa[1].get(0); // OK

関連記事:

JavaのジェネリックスのTと疑問符(ワイルドカード)の違い

Javaのジェネリックスの詳しい説明

以上がJava の汎用ワイルドカードと有界型パラメータの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。