ホームページ  >  記事  >  Java  >  Java のジェネリックスの型シールド機能はコードにどのような影響を与えますか?

Java のジェネリックスの型シールド機能はコードにどのような影響を与えますか?

WBOY
WBOY転載
2023-04-26 13:34:081236ブラウズ

ジェネリックを使用して型の違いを保護する

C 言語には、パラメーター化された型を使用して一般的なバージョンを作成し、コンパイラーがさまざまな型の特定のバージョンを自動的に生成できる非常に便利なテンプレート関数があります。 Java 言語には、ジェネリックスと呼ばれる同様の関数があります。クラスとメソッドを作成するときは、一般に特定の型が使用され、ジェネリックスを使用して型をパラメータ化できるため、より一般的なコードを作成できます。

多くの人は、C テンプレート (テンプレート) と Java ジェネリック (ジェネリック) の 2 つの概念が同等であると信じていますが、実際には実装メカニズムはまったく異なります。 C テンプレートは一連のマクロ命令であり、コンパイラは各型のテンプレート コードのコピーを作成します。Java ジェネリックの実装は、本質的に型制限の構文糖である「型消去」の概念に基づいています。

1. ジェネリック クラス

サポート クラスを例として、ジェネリックの一般サポート クラスを定義します:

/** 通用支撑类 */@Getter@Setter@ToStringpublic class GenericHolder<T> {    /** 通用取值 */
    private T value;    /** 构造函数 */
    public GenericHolder() {}    /** 构造函数 */
    public GenericHolder(T value) {        this.value = value;
    }
}

2. ジェネリック インターフェイス

定義汎用データ プロバイダー インターフェイス:

/** 数据提供者接口 */public interface DataProvider<T> {    /** 获取数据函数 */
    public T getData();
}

3. 汎用メソッド

汎用シャロー コピー関数の定義:

/** 浅拷贝函数 */public static <T> T shallowCopy(Object source, Class<T> clazz) throws BeansException {    // 判断源对象
    if (Objects.isNull(source)) {        return null;
    }    // 新建目标对象
    T target;    try {
        target = clazz.newInstance();
    } catch (Exception e) {        throw new BeansException("新建类实例异常", e);
    }    // 拷贝对象属性
    BeanUtils.copyProperties(source, target);    // 返回目标对象
    return target;
}

4. 汎用ワイルドカード

汎用ワイルドカードは通常、「」を使用します。 ?" は特定の型引数の代わりに使用されます。"?" はすべての型の親クラスとみなすことができます。特定の型が不明な場合は、汎用ワイルドカード「?」を使用できます。その型の特定の関数を使用する必要がなく、Object クラスの関数のみを使用する場合は、汎用ワイルドカード「?」を使用できます。

/** 打印取值函数 */public static void printValue(GenericHolder<?> holder) {
    System.out.println(holder.getValue());
}/** 主函数 */public static void main(String[] args) {
    printValue(new GenericHolder<>(12345));
    printValue(new GenericHolder<>("abcde"));
}

Java 仕様では、一般的なワイルドカード「?」の使用は推奨されていません。上記の関数は次のように変更できます:

/** 打印取值函数 */public static <T> void printValue(GenericHolder<T> holder) {
    System.out.println(holder.getValue());
}

5. 一般的な上限と下限

ジェネリックスを使用する場合、型の場合、渡されるジェネリック型の実パラメータの上限と下限を設定することもできます。たとえば、型の実パラメータは、特定の型の親クラスまたは特定の型のサブクラスでのみ渡すことができます。 。ジェネリック型の上限と下限の宣言は、ジェネリック型の宣言と一緒に配置する必要があります。

上限ワイルドカード (extends):

上限ワイルドカードは「extends」で、指定された型またはそのサブクラスを一般パラメータとして受け入れることができます。指定された型のサブクラスであるだけでなく、特定のインターフェイスを実装する必要があることを指定する特別な形式もあります。例: List は、これが A の特定のサブクラスのリストであり、保存されるオブジェクトは A または A のサブクラスである必要があることを示します。 List リストの場合、A または A のサブクラス オブジェクトを追加することはできませんが、A のオブジェクトを取得することのみが可能です。

下限ワイルドカード (スーパー):

下限ワイルドカードは「スーパー」で、指定された型またはその親クラスを一般パラメーターとして受け入れることができます。例: List は、これが A の特定の親クラスのリストであり、保存されるオブジェクトは A または A のスーパークラスである必要があることを示します。 List リストの場合、A または A のサブクラス オブジェクトを追加できますが、取得できるのは Object のオブジェクトのみです。

PECS (Producer Extends Consumer Super) 原則:
プロデューサとしてデータを提供する (読み出す) 場合、上限のワイルドカード (拡張) を使用するのが適切です;
データを消費するコンシューマとして (読み取り時)、書き込み時)、下限ワイルドカード (スーパー) を使用するのが適切です。

日常のコーディングでは、上限ワイルドカード (拡張) がより一般的に使用され、ジェネリック型の親クラスを制限するために使用されます。コード例は次のとおりです:

/** 数字支撑类 */@Getter@Setter@ToStringpublic class NumberHolder<T extends Number> {    /** 通用取值 */
    private T value;    /** 构造函数 */
    public NumberHolder() {}    /** 构造函数 */
    public NumberHolder(T value) {        this.value = value;
    }
}/** 打印取值函数 */public static <T extends Number> void printValue(GenericHolder<T> holder) {
    System.out.println(holder.getValue());
}

以上がJava のジェネリックスの型シールド機能はコードにどのような影響を与えますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。