Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

Javaのジェネリクス(Generics/総称型)とは?

ジェネリクスとは、クラスやメソッドにデータ型名を「<>」記号でくくることで、String型やInteger型などの指定した型に対応する多用途型なクラスやメソッドを作る機能のことをいいます。

以下のような、リストに入れる型の限定などがよく見られるジェネリクスです。

List<String> arr = new ArrayList<String>();

通常、Listにはさまざまなものを入れられますが、 「<String>」を付けると入れられる型がStringに限定されます。

ジェネリクスを使うメリットは?

たとえば、上記のリストにIntegerを入れると、Stringではないのでコンパイルエラーになります。

そのため、ジェネリクスを使うとコンパイルエラーが出るのでコードの記述ミスが見つかりやすいです。

また、型を限定しているためコード上で何の型を扱っているかわかりやすくなっています。

ポテパンダの一言メモ

ジェネリクスを使うと、

1. コードの記述ミスが見つかりやすい

2.コード上で何の型を扱っているかわかりやすい

といったメリットがあります。

ジェネリクスのネーミング慣例

特に決められてはいないのですが、ジェネリクスの変数名は基本的に1字で定義します。

また、以下のような慣例があるので覚えておくとよいでしょう。

ジェネリクスのネーミング慣例
  • E:Element(要素)
  • K:Key(キー)
  • T:Type(タイプ)
  • V:Value(値)
  • N:Number(数値)
  • S,U:2,3番目

クラスでのジェネリクスの書き方

クラスでジェネリクスを使う方法を見ていきましょう。

class GenericSample<T>{
    private T value;

    public GenericSample(T val){
        this.value = val;
    }

    public T getValue(){
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        // String型のジェネリクス
        GenericSample<String> cstr = new GenericSample<String>("Hello ポテパン!");
        String str = cstr.getValue();
        System.out.println(str);

        // Integer型のジェネリクス
        GenericSample<Integer> cint = new GenericSample<Integer>(100);
        Integer inum = cint.getValue();
        System.out.println(inum);
    }
}

上記のサンプルコードは、GenericSampleクラスに「<T>」を記述しました。

「<T>」を記述すると、「Object型」から「T型(型変数)」にデータ型の指定が変わります。

mainメソッド内でGenericSampleクラスをインスタンス化する場合には、データ型を「<>」記号で指定します。

このサンプルコードでは<String>と<Integer>で指定していますね。

getValueメソッドは、ジェネリクスを使っているため型変換(キャスト)することなく、指定した型に値を代入できています。

そのため、データ型が一致しないエラーが出ずに複数の型で使用可能になっているのです。

このサンプルコードを実行すると、以下の実行結果が得られます。

実行結果↓

Hello ポテパン!
100

ジェネリクスのワイルドカード型とは?

ジェネリクスのワイルドカード型とは、型に「?」記号が付いているジェネリクス型です。

ワイルドカードを利用すると、プログラムが実行されるまで型が不明なものとして表せます。

ワイルドカード型には、「非境界ワイルドカード型」「境界ワイルドカード型」の2種類あり、それぞれ以下のように分けられます。

ひとつずつ解説しますね。

1.非境界ワイルドカード型

非境界ワイルドカード型は、型が「?」のみのジェネリクス型を言います。

実型のパラメータが決まっていない場合などに利用されます。

具体的なコードを見てみましょう。

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
      checkAnyKindOfList(new ArrayList());
      checkAnyKindOfList(new ArrayList());
    }

    public static void checkAnyKindOfList(List<?> list) {
        Object o = list.get(0);
    }
}

checkAnyKindOfListメソッドは、引数にどんな制約が付いたListでも渡せます。

しかし、何が渡されるかは不明です。

checkAnyKindOfListメソッドでは、要素の取り出しなど「要素の制約がわからなくても行える操作」であれば実行可能です。

反対に、要素の追加など「要素の制約がわかっていないと行えない操作」はできません。

このサンプルコードを実行すると、java.lang.IndexOutOfBoundsExceptionエラーが発生します。(サイズが設定されていないためです)

2.境界ワイルドカード型

境界ワイルドカード型は、型にある程度の幅(上下限)をもたせて宣言できるジェネリクス型を言います。

境界ワイルドカード型には「上限付き境界ワイルドカード」と「下限付き境界ワイルドカード」の2種類あります。

それぞれの使い方を見ていきましょう。

1.上限付き境界ワイルドカード(extends)

上限付き境界ワイルドカードでは、「?」と「extends」を用います。

サンプルコードで動きを確認しましょう。

class GenericSample<T>{
    private T value;

    public GenericSample(T val){
        this.value = val;
    }

    public T getValue(){
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        // Integer型のジェネリクス
        GenericSample<Integer> gnum1 = new GenericSample<Integer>(100);
        Integer inum = gnum1.getValue();
        System.out.println(inum);

        // Number型のジェネリクス(ワイルドカードを使用)
        GenericSample<? extends Number> gnum2;
        gnum2 = gnum1;
        Number num = gnum2.getValue();
        System.out.println(num);
    }
}

GenericSampleクラスの型変数Tは不明な型です。

そこで「<? extends Number>」を記述すれば、NumberクラスまたはNumberクラスのサブクラスのみOKという境界が設定されます。

実行結果↓

100
100

2.下限付き境界ワイルドカード(super)

下限付き境界ワイルドカードでは、「?」と「super」を用います。

class GenericSample<T>{
    private T value;

    public GenericSample(T val){
        this.value = val;
    }

    public T getValue(){
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        // Object型のジェネリクス
        GenericSample<Object> gobj = new GenericSample<Object>("ポテパン");
        // String型のジェネリクス(ワイルドカードを使用)
        GenericSample<? super String> gstr;
        gstr = gobj;
        Object obj = gstr.getValue();
        System.out.println(obj);
    }
}

「<? uper String>」を記述して、StringクラスまたはStringクラスの親クラスのみOKという境界が設定されます。

実行結果↓

ポテパン

メソッドでのジェネリクスの書き方

ジェネリクスは、クラスだけではなくメソッドでも使用可能です。

メソッドで利用する場合は、戻り値の型名Tの前に「<T>」を記述します。

サンプルコードで動きを確認してみましょう。

public class Main {
    public static void main(String[] args) {
        String str = getValue("ポテパンとジェネリクスを学ぶ");
        System.out.println(str);
 
        Number num = getValue(300);
        System.out.println(num);
    }
    private static <T> T getValue(T t){
        return t;
    }
}

getValueメソッドの引数と戻り値にT型を指定します。

また、クラスと同様にgetValueメソッドをキャストの必要はありません。

実行結果↓

ポテパンとジェネリクスを学ぶ
300

ジェネリクス複数の型パラメータ

ジェネリクスは、カンマ区切りで複数の型パラメータの使用も可能です。

サンプルコードを記述します。

class GenericSample<V, N>{
    private V v;
    private N n;

    public GenericSample(V v, N n){
        this.v = v;
        this.n = n;
    }

    public V getV(){
        return v;
    }

    public N getN(){
        return n;
    }
}
public class Main {
    public static void main(String[] args) {
      GenericSample<String, Integer> sample = new GenericSample<>("ポテパン", 500);

      String str = sample.getV();
      Number num = sample.getN();

      System.out.println(str);
      System.out.println(num);
    }
}

実行結果↓

ポテパン
500

まとめ

Javaのジェネリクスについて意味や使い方を紹介しました。

ジェネリクスを利用すれば、さまざまなデータ型で似たような処理を動かしたい場合にそれぞれ処理を記述しなくて済みます。

また、 コードの記述ミスが見つかりやすくなったり、何の型を扱っているかわかりやすいといったメリットもあります。

ジェネリクスを活用する際は、ぜひこの記事を参考にしてください!

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。