Wiki内検索
カウンタ
メニュー
最近更新したページ
最新コメント
トップページ by awesome things!
トップページ by check it out
Generics(Java) by stunning seo guys
String(Java) by awesome things!
トップページ by check it out
PHPのページ by stunning seo guys
Tomcatのページ by stunning seo guys
トップページ by check it out
トップページ by awesome things!
タグ

Genericsと型引数の応用(Java)


型引数の応用

ここでは、Genericsで導入された「型引数」について、いくつかもサンプルを示したいと思います。


型引数を受け取るクラスのサンプル

「型引数」を受け取るクラスを作って見ましょう。同時にメソッドにも型を引数で渡すようにします。

<Action.java>
package beans;

public abstract class Action {

    public Action() {
        super();
    }

    abstract public void doIt();

}

<Eat.java>
package beans;

public class Eat extends Action{
    String food;

    public Eat(String _food) {
        this.food=_food;
    }

    public void doIt() {
        System.out.println(food + "を食べました。");
    }
}

これら2つのクラスは継承関係にあります。

次にこのActionクラスを仕様するクラスを作成します。

<SomethigToDo.java>
package beans;

public class SomethigToDo<E extends Action>{ // (a)

    public SomethigToDo() {
        super();
    }

    public void justDoIt(E obj){
        obj.doIt(); // (b)
    }
}

このクラスはEを型引数として受け取ります。抽象したActionクラスを使うことを宣言するのが、(a)行の<E extends Action>の部分で、これにより、ActionクラスのメソッドであるdoIt()メソッドが呼べるようになります(Actionクラスの利用を宣言しないと、(b)行の

obj.doIt();

がコンパイルエラーとなります)。

次にこのSomethigToDoクラスを使用するクラスを作成します。

<ExampleGenerics2.java>
package test;

import beans.Eat;
import beans.SomethigToDo;

public class ExampleGenerics2 {

    public static void main(String[] args) {

        SomethigToDo<Eat> _act = new SomethigToDo<Eat>();
        String _str = "バナナ";
        _act.justDoIt(new Eat(_str));
    }
}

実行結果は以下のようになります。

バナナを食べました。


型引数を受け取るクラスのサンプル2

上で示したサンプルでは、SomethingToDoクラスが抽象クラスActionを利用することで、具象クラスEatとSomethingToDo間である程度の祖結合を実現していました。

以下ではこれをもう少し推し進めてみましょう。

<ActionInterface.java>
package beans;

public interface ActionInterface {

    abstract public void doIt();

}

次にAction.javaを以下のように直します。

<Action.java>
package beans;

public abstract class Action implements ActionInterface {}

他のプログラムに変更はありません。これで、定石通りメソッドをインターフェイスで記述することができました。でも、かなり冗長な感じがしますね。これは、SomethingToDo.javaの(a)がextendsをサポートしている反面、implementsをサポートしていないためです(このため、一度、Action.javaという空のクラスを経由しています)。


型引数を受け取るメソッドのサンプル

次は「メソッドが型引数を受け取る」サンプルを作ってみます。
以下の2つのクラスを作ってみましょう。

<SomethigToDo1.java>
package beans;

import java.util.List;

public class SomethigToDo1{

    public SomethigToDo1() {
        super();
    }

    public void justDoIt(List<? extends Action> obj){
        for(Action el : obj){ // (A)
            el.doIt();
        }
    }
}

<ExampleGenerics2.java>
package test;

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

import beans.Eat;
import beans.SomethigToDo1;

public class ExampleGenerics3 {

    public static void main(String[] args) {

        List<Eat> _list = new ArrayList<Eat>();
        _list.add(new Eat("バナナ"));
        _list.add(new Eat("イチゴ"));
        _list.add(new Eat("パイナップル"));

        SomethigToDo1 _act = new SomethigToDo1();
        _act.justDoIt(_list);

    }
}

他のプログラムは変えません。実行結果は以下のようになります。

バナナを食べました。 イチゴを食べました。 パイナップルを食べました。

もう少し突っ込んでみましょう。以下の2つを作ってみましょう。

<Drink.java>
package beans;

public class Drink extends Action{
    String drink;

    public Drink(String _drink) {
        this.drink=_drink;
    }

    public void doIt() {
        System.out.println(drink + "を飲みました。");
    }
}

<ExampleGenerics4>
package test;

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

import beans.Action;
import beans.Drink;
import beans.Eat;
import beans.SomethigToDo1;

public class ExampleGenerics4 {

    public static void main(String[] args) {

        List<Action> _list = new ArrayList<Action>();
        _list.add(new Eat("バナナ"));
        _list.add(new Drink("イチゴジュース"));
        _list.add(new Eat("パイナップル"));
        _list.add(new Drink("ブドウジュース"));

        SomethigToDo1 _act = new SomethigToDo1();
        _act.justDoIt(_list);

    }
}

このサンプルは簡単なストラテジーパターンになっています。

先ほども述べましたが、Genericsはインターフェイス・プログラミングに固執すると冗長性を持つように思いますが、抽象化を促進することでクラス間の祖結合化をサポートするものとも考えることができると思います。

(インターフェイスではなく)「抽象クラスによる祖結合」という感触です。
2007年02月27日(火) 19:57:49 Modified by wanderingse




スマートフォン版で見る