javaのGenericが めっめっ! すぎる - '総称配列' と戦った

Generic を使ったクラスを自前で創ろうとすると、とたんにいろんな所で詰まる…。 今回はコレに詰まりました

class Dolls<T>
{
    int m_n;

    abstract private class IRozenMaiden
    {
        abstract String getSuffix();
    }

    class Suigintou extends IRozenMaiden
    {
        public String getSuffix()
        {
            m_n = 0;
            return "だわぁ〜";
        }
    }

    class Kanaria extends IRozenMaiden
    {
        public String getSuffix()
        {
            m_n = 1;
            return "かしらー";
        }
    }

    class Suiseiseki extends IRozenMaiden
    {
        public String getSuffix()
        {
            m_n = 2;
            return "ですぅ〜";
        }
    };

    void kunkun()
    {
        // ↓Dolls<T>.IRozenMaiden の総称配列を作成できません。
        IRozenMaiden[] pcRozen = new IRozenMaiden[]
        {
            new Suigintou(),
            new Kanaria(),
            new Suiseiseki(),
        };
    }
}


class a
{
    static void main(String[] args)
    {
        Dolls<String> d = new Dolls<String>();
        d.kunkun();
    }
}


Dolls<T>#IRozenMaiden の配列が作れないと怒られてます。

Java 総称配列」でぐぐると、java の仕様にガッカリしている様子がわんさか出てきます が、引っかかれた方のコードを見ると「Generic型の配列作成時に意味不明に怒られてぐんにょり」というパターンです。 こんな感じ。

// ↓エラー。総称配列が作れません。
ArrayList<IRozenMaiden>[] rozenMaidens = new ArrayList<IRozenMaiden>[8];

// 仕方ないのでこうするか…
ArrayList[] rozenMaidens = new ArrayList[8];

// いろきゅう的には、コレでもえぇんちゃうの?
// と思うも、そこには複雑な大人の事情があるに違いないのだ。
// よい子はその大人の都合に触れてはならぬ。触らぬ神に祟りなしなのだ。
ArrayList<ArrayList<IRozenMaiden> > rozenMaidens =
    new ArrayList<ArrayList<IRozenMaiden> >(8)


この時点で、正直「どうかなー」とは思ってみるんですが(ぉ)それはとりあえず置いといて…




今回のおいらの問題点は、Generic なクラスの配列なんて創ってないんですよ。


Generic型の配列なんて作ってません!

さて、私のところで遭遇してしまった「総称配列が作れません」問題ですが、コード見る限りは 別に Generic の配列なんて作っていません。 Dolls<T>#kunkun() の中で、同じクラス内の IRozenMaiden を利用しているだけなんですよ。 これは正直意味が分からない。

class Dolls<T>
{
    abstract private class IRozenMaiden
    {
        abstract String getSuffix();
    }

    void kunkun()
    {
        // ↓Dolls<T>.IRozenMaiden の総称配列を作成できません。
        IRozenMaiden[] pcRozen = new IRozenMaiden[]
        {
            new Suigintou(),
            new Kanaria(),
            new Suiseiseki(),
        };
    }
}

Dolls<T>が原因ではあるんでしょうけれども、どー書けと…。 と、試行錯誤した結果、こうなりました。

class Dolls<T>
{
    abstract private class IRozenMaiden
    {
        abstract String getSuffix();
    }

    void kunkun()
    {
        // パス指定 且つ "?" で指定で、警告無しに
        Dolls<?>.IRozenMaiden[] pcRozen = new Dolls<?>.IRozenMaiden[]
        {
            new Suigintou(),
            new Kanaria(),
            new Suiseiseki(),
        };
    }
}

えー



kunkun() から Dolls<T> の型が見えている *1 はずなのに指定しなきゃならない…ってか指定しても "?" のワイルドカード指定しなくてはならないとかマジ何コレ。(T を型引数に渡してもエラーの内容は変わらなかった)



んまぁ、Dolls<T> のインナークラスは、暗黙に Dolls<T> の this を受け取る故に、なんかゴニョゴニョあるんでしょうけれど… コレは正直面倒だと思う。見栄えも良くないし。


Java の Generic は使いづらいわ。 Collectionクラス専用って方向で利用した方がいいのかも…

ちなみに

Dolls<T> のインナークラス

  • IRozenMaiden
  • Suigintou
  • Kanaria
  • Suiseiseki

の全てに static をつけると、配列作成時の Dolls<T> の修飾は不要になります。 が、そうすると Dolls<T> のメンバにはアクセス出来なくなります。

C++屋としては、そもそもインナークラスから親クラスのメンバにアクセス出来ること自体がおかしい気はしますが…でもこの機能、正直便利なんだよなぁ…(ぉ

ちなみに2

ArrayList<?>[] rozenMaidens = new ArryaList[8];

は有効でした。 警告が無くなりましましたが、結局 Object のコレクションです。^^;


思う事

  • Java はもうそろそろ作り直すなんじゃ無かろうかと個人的に思う。 Javaの v2系 に勝手に期待してます。
  • やっぱ template 最高だわ。

*1:クラスのメンバなんだから当たり前