ジェネリクスをやっと理解した

前提条件

Javaには型安全という考え方があります。

型安全という考え方は名前の通り、「変数やメソッドに型を指定して安全にプログラムを組み立てていきましょう!」という考え方です。

 

例えば、型の指定をしていない変数mojiに1を代入したとします。

この変数mojiには1という文字が入っているのですが、文字なのか数字を判別することができませんよね。

自分からすると文字の1だと考えて定義した変数が自分以外の誰かからすると数字の1と捉えてしまう可能性があります。

その可能性を潰すためにも型を指定することがJavaのルールになっています。

public class Num {
   public static void main(String args[]) {
     String moji = "1";

      System.out.println(moji);

     System.out.print(moji + moji);    //11

    /*変数mojiがint型だった場合
        System.out.println(moji + moji);
        --2
    */
    }

}

ちなみにJavaを勉強する前はPHPを独学で学んでいたのですが、PHPのような変数やメソッドに型を指定しない言語を動的型付け言語と言いいます。
それに対してJavaのような明示的に型を指定しないといけない言語を静的型付け言語と言います。
僕のようにPHPのような動的片付け言語から移行してきたから人からするとストレスを感じる部分なので少しづつなれていきましょう!

ジェネリクスとは

Javaは型を指定して安全にプログラムを組まないといけない言語という事が理解できたところで本題です。

 

ジェネリクスとは、コレクションに対して型を指定する方法です!

コレクションとは値の追加、保持などができるjava特有の配列のようなものです。(厳密には配列ではない)

 

下記のコードを見れば分かると思うのですが、

boxという名前のコレクションの型をStringとして指定することにより、文字列しか格納できないコレクションになりました。

//<>の部分にStringを指定!文字列しか格納できないコレクション
List<String> box = new ArrayList<String>();
box.add("hello");
box.add("bye");

for(String i: box) {
	System.out.println(i);
	}
配列とコレクションの違い
どちらも複数の値を保持できる変数と考えて問題ないのですが、
配列は型の情報、格納する値などを定義する段階で指定しなければいけなく、途中で値の追加などはできません。
それに対してコレクションは名前を宣言するだけで良く、途中で値の追加などができます。

ジェネリクスの使用目的

ジェネリクスの使用目的を考える前にコレクションの使用目的を考えてみましょう。

コレクションは複数の値を好きなだけ入れきれることができる配列のようなもなので、何かに関連したデータをまとめて扱いたい時に使用しますよね。

  • ポジション→{ガード、フォワード、センター}
  • 美味しいご飯→{寿司、蟹、ハンバーグ、味噌汁、}

上記のようにまとめることで関連する情報をまとめておくことで後で使用する時に何かと便利です。

 

そのためコレクションを使用するときはまとめた情報を繰り返し処理するループ処理などと併用されます。

ここで、問題になってくるのがコレクションには複数の値を入れきれるということです。

 

例えば下記のようなコレクションがあった時はどうでしょうか?

public static void main(String args[]){
  List<> box = new ArrayList<>();
  box.add(1);
  box.add("aiueo");
  box.add("hello");
  //boxの中身→{数字の1、文字列のaiueo、文字列のhello}

for(String i: box){
  System.out.println(box);  //文字列でループ処理を回す処理なのでエラーになる
}

このようなコードだと様々な型が格納されておりループ処理の中で使用するのができません。

そこで、ジェネリクスを使用してコレクションの型を指定し一つの型だけを格納できるコレクションとしてせんげんしてあげます。

public static void main(String args[]){
  List<String> box = new ArrayList<String>();  //String型として扱う宣言
  box.add("1");
  box.add("aiueo");
  box.add("hello");

  for(String i: box){
    System.out.println(box);  //文字列しか格納していないのでエラーにならない
  }
}

このように<型名>を記述することでコレクションをどのように扱うかを定めたるものがジェネリクスになります。

こうすることで一つの型しか格納できなくなるので型安全が保てますよね!

便利なコレクションを安全に使うことができるジェネリクスです!

便利な使い方

ジェネリクスを便利に使うなら宣言時にEという文字を設定して宣言しておき、呼び出す時に型を定義するという方法があります。

<E>と記述した部分は「T」でも「Z」でも「aiueo」等なんでも問題ないです。

このような代替文字を置いておくことで「呼び出し時に型を定義してね」という意味になります。

メソッドを例えば個人が作成したHero型に設定することも可能なので、ケースに合わせた型宣言が可能になります。

//メソッドの型をEとしておく
public void Box<E>{
  System.out.println("ジェネリクス");
}

public static void main(String args[]){
  Box<String> b = new Box<String>;
  Box<int> b = new Box<Integer>;
}

Twitterでフォローしよう

読んでみーな
おすすめの記事