西海岸より

つらつらざつざつと

ジェネリクスを使ったインタフェースの実装方法

"Java並行処理プログラミング"の第八章で、Puzzleインタフェースを実装しようとしたけど、どう実装していいのかわからなかった顛末のメモ。結局著者Brian Goetzにまでメールして解決しました。

実装しようとしてたのは以下のPuzzleインタフェース。

Listing 8.13. Abstraction for Puzzles Like the "Sliding Blocks Puzzle". (Puzzle.java)

public interface Puzzle<P, M> {
   P initialPosition();
   boolean isGoal(P position);
   Set<M> legalMoves(P position);
   P move(P position, M move);
}

(http://book.javanb.com/java-concurrency-in-Practice/ch08lev1sec5.html)


これを以下のように実装しようとしてた。(Position Movementクラスは別途実装済み)

class DefaultPuzzle<Position, Movement> implements Puzzle<Position, Movement>{
    int map[][]; // 0:road, 1:wall
    int size;
    final static int defaultSize = 100;
    
    public DefaultPuzzle(int size) {
        if(size < 2) 
            throw new IllegalArgumentException("Size must be more than 2.");
        this.size = size;
        map = new int[size][size];
    }

    public Position initialPosition() {
        if(map[0][0] != 0)
            throw new IllegalStateException("position[0,0] must be vacant."); 
        return new Position();
    }
}

それでコンパイルすると、、、エラー。

Puzzle.java:29: 予期しない型
検出値 : 型パラメータ Position 
期待値 : クラス
return new Position();
                ^

なんでだろうと考えると、ジェネリクスで宣言してるクラスはnewできないため。それはそうなんだけれど、そうするとPuzzleをimplementするクラスではPositionやMovementのインスタンスを作れないのではと、はまってしまった。

結局わからなかったので、著者Brian Goetzにメールしたところ5分で返信が来た。以下のようにすれば良いと。

class DefaultPuzzle implements Puzzle<Position, Movement> { ... }

orz

そりゃそうだ。

イメージとしては、PuzzleインタフェースのPとMの型を設定し、implementするといったところなのかな。ともかくも解決して良かった。。


復刊投票ページ
http://www.fukkan.com/fk/VoteDetail?no=46255&tr=b

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―