Javaのジェネリックスの詳細な説明

高洛峰
リリース: 2017-01-18 10:54:11
オリジナル
1365 人が閲覧しました

いわゆるジェネリック: クラスとインターフェイスを定義するときに型パラメーターを指定できます。この型パラメーターは、変数を宣言し、オブジェクトを作成するときに決定されます (つまり、型引数とも呼ばれる実際の型パラメーターを渡します)。ジェネリック クラスまたはインターフェイス

"ダイヤモンド" 構文

//定义
 
public interface List<E> extends Collection<E>  
 
public class HashMap<K,V> extends AbstractMap<K,V>  implements Map<K,V>, Cloneable, Serializable 
//使用
 
List<String> list = new ArrayList();
 
//Java7以后可以省略后面尖括号的类型参数
 
List<String> list = new ArrayList<>();
ログイン後にコピー

ジェネリック クラスからサブクラスを派生する

//方式1
 
public class App extends GenericType<String>
 
//方式2
 
public class App<T> extends GenericType<T>
 
//方式3
 
public class App extends GenericType
ログイン後にコピー

疑似ジェネリック

真のジェネリック クラスは存在せず、ジェネリック クラスは Java 仮想マシンに対して透過的です。JVM は認識しません。ジェネリック クラスの存在。つまり、JVM はジェネリック クラスを通常のクラスと何ら区別せずに扱います。そのため、静的メソッド、静的初期化ブロック、および静的変数では型パラメータを使用できません。

- 以下のメソッドはすべて間違っています

private static T data;
 
static{
 
    T f;
 
}
 
public static void func(){
 
    T name = 1;
 
}
ログイン後にコピー

次の例は、ジェネリック クラスが存在しないことを側から検証できます

public static void main(String[] args){
 
        List<String> a1 = new ArrayList<>();
        List<Integer> a2 = new ArrayList<>();  
    System.out.println(a1.getClass() == a2.getClass());
 
    System.out.println(a1.getClass());
 
    System.out.println(a2.getClass());
 
}
ログイン後にコピー

Output

true
 
class java.util.ArrayList
 
class java.util.ArrayList
ログイン後にコピー

Type wildcard

まず第一に、Foo が親であるかどうかを明確にする必要がありますBar のクラスですが、List は List の親クラスではありません。Java では、汎用のワイルドカードを表すために「?」を使用します。この種のワイルドカードを使用した .List ジェネリックは、要素を設定 (set) することはできませんが、要素を取得 (get) することしかできません。プログラムはリスト内のタイプを判断できないため、オブジェクトを追加できません。ただし、取得されるオブジェクトは Object 型である必要があります。

次のメソッドはコンパイル エラーになります:

List<?> list = new ArrayList<>();
 
list.add(new Object());
ログイン後にコピー

いくつかのアイデア:

1. List オブジェクトは List オブジェクトとして使用できません。 ;オブジェクト>クラスのサブカテゴリ。

2. 配列とジェネリックは異なります。Foo が Bar のサブタイプ (サブクラスまたはサブインターフェイス) であると仮定すると、Foo[] は依然として Bar[] のサブタイプですが、 G は G ではありません。

3. さまざまなジェネリック リストの親クラスを表すには、型ワイルドカードを使用する必要があります。List コレクションに型引数として疑問符を渡します。 ;?>( 不明なタイプの要素のリストを意味します)。この疑問符 (?) はワイルドカード文字と呼ばれ、その要素の型は任意の型に一致します。

ワイルドカードの上限

List は、すべての SuperType ジェネリック リストの親クラスまたはそれ自体を表します。ワイルドカードの上限を持つジェネリックスは set メソッドを持つことができず、get メソッドのみを持つことができます。

ワイルドカードの上限を設定すると、次の問題を解決できます: Dog は Animal サブクラスであり、受信リストの数を取得する getSize メソッドがあります。コードは次のとおりです

abstract class Animal {
    public abstract void run();
}
class Dog extends Animal {
    public void run() {
        System.out.println("Dog run");
    }
}
public class App {
    public static void getSize(List<Animal> list) {
        System.out.println(list.size());
    }
    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        getSize(list); // 这里编译报错
    }
}
ログイン後にコピー

ここでのプログラミング エラーの理由は次のとおりです。 List は List の親クラスではありません。 1つ目の解決策は、getSizeメソッドの仮パラメータListをListに変更することですが、この場合はオブジェクトを取得するたびに強制的な型変換が必要となり面倒です。ワイルドカードの上限を使用すると、List を List に変更することができ、コンパイルが間違ってしまうことはなく、型変換は必要ありません。


ワイルドカード

Listの下限は、SubTypeジェネリックリストの下限を表します。ワイルドカードの上限を持つジェネリックには get メソッドを含めることはできず、set メソッドのみを含めます。

ジェネリックメソッド

型パラメータを使用せずにクラスまたはインターフェイスを定義するが、メソッドを定義するときに型パラメータを自分で定義したい場合、JDK1.5 ではジェネリックメソッドもサポートされています。ジェネリック メソッドのメソッド シグネチャには、通常のメソッドのメソッド シグネチャよりも多くの型パラメータ宣言が含まれます。複数の型パラメータ宣言は、すべてのメソッドの間にカンマ (,) で区切られます。修飾子とメソッドの戻り値の型の構文形式は次のとおりです:

修饰符 返回值类型 方法名(类形列表){
 
//方法体
 
}
ログイン後にコピー

ジェネリック メソッドでは、メソッドの 1 つ以上のパラメーター間の型の依存関係、またはメソッドの戻り値とパラメーター間の型の依存関係を表現するために型パラメーターを使用できます。このような型の依存関係がない場合は、ジェネリック メソッドを使用しないでください。 Collections の copy メソッドは、ジェネリック メソッドを使用します:

 public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
ログイン後にコピー

このメソッドでは、src 型が dest 型またはそれ自体のサブクラスである必要があります。

消去と変換

厳密なジェネリック コードでは、ジェネリック宣言を持つクラスは常に型パラメーターを持つ必要があります。ただし、古い Java コードとの一貫性を保つために、型パラメータを指定せずにジェネリック宣言を持つクラスを使用することもできます。このジェネリック クラスに型パラメーターが指定されていない場合、型パラメーターは raw 型と呼ばれ、パラメーターの宣言時に指定された最初の上限型がデフォルトになります。

ジェネリック情報を持つオブジェクトをジェネリック情報のない別の変数に代入する場合、山かっこ内のすべての型情報は破棄されます。たとえば、List 型を List に変換すると、List のコレクション要素の型チェックが型変数 (つまり、Object) の上限になります。この状況を消去と呼びます。

class Apple<T extends Number>
 
{
 
 T size;
 
 public Apple()
 
 {
 
 }
 
 public Apple(T size)
 
 {
 
  this.size = size;
 
 }
 
 public void setSize(T size)
 
 {
 
  this.size = size;
 
 }
 
 public T getSize()
 
 {
 
  return this.size;
 
 }
 
}
 
public class ErasureTest
 
{
 
 public static void main(String[] args)
 
 {
 
  Apple<Integer> a = new Apple<>(6);    // ①
 
  // a的getSize方法返回Integer对象
 
  Integer as = a.getSize();
 
  // 把a对象赋给Apple变量,丢失尖括号里的类型信息
 
  Apple b = a;      // ②
 
  // b只知道size的类型是Number
 
  Number size1 = b.getSize();
 
  // 下面代码引起编译错误
 
  Integer size2 = b.getSize();  // ③
 
 }
 
}
ログイン後にコピー

Java のジェネリックスの詳細な説明に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!