読者です 読者をやめる 読者になる 読者になる

プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

JAVAでジェネリック型の配列を作って返したい(´・ω・`)

JAVA

JAVAのジェネリクスではジェネリック型の配列は作れないけど、何となく作りたい場面があった。
良くあるのはObject型で作っておいて、後で返すときとかにキャストという方法。でも嫌ジャン。
 
T t = (T) new Object[obj.length];
で、一見T型の配列が出来た様に見えるけど、tのクラスを見たら[L java.lang.Object型のオブジェクトだもん。
ということは、自分か自分のスーパークラスにしかキャストできないからTがString型だったとしても、String s = (String)t;ということは出来ない。じぇんじぇん使えない。
(ちなみに、T t =(T) new Object[obj.length]が成立するのは、コンパイルすると結局のところObject t=(Object)new Object[obj.length]と書き換わり、矛盾が生じないからだ。)
 
 
つーわけで、ちゃんと[L T型のオブジェクトになって欲しい。
 
 
というわけで、何となくやってみたらそれっぽい物が出来た。

import java.lang.reflect.Array;
public class GTest {
    public static void main(String args) {
        String
s = {};
        System.out.println(generev(s));
    }

    @SuppressWarnings("unchecked")
    public static <T> T generev(T obj){
        if(obj==null)return null;
        T t = (T) Array.newInstance(obj.getClass().getComponentType(), obj.length);
        for(int i=0;i < obj.length;i++){
            t[t.length-i-1] = obj[i];
        }
        return t;
    }
}
結果は [Ljava.lang.String;@10b30a7 で、ちゃんとStringの配列型が返ってきてる。
 
uncheckedしてるけど、Array.newInstanceで作成されるオブジェクトは[L T型で、TはObjectと実行時は処理されるので安全です。(ちなみに、T型配列にキャストするところは実行時にはObject→Objectの変換なので完全に無駄だけど、プログラムする上では型安全が保持できそうな出来なさそうなでやっておいた。)

完全に勘違いしていました。newInstanceで返ってくるオブジェクトはObject型で返ってくるので、Object型の配列にするにしてもキャストする必要があります。無駄ではありません。

 
 
でも、これは完璧じゃないんだよね。
例えば
Integer i ={1,2};

Number
n =GTest.<Number>generev(i);

と書いても、返ってくる配列はNumber型じゃなくてInteger型になってしまう。Tという物がコンパイルするとObjectと同義になる以上、これは解決出来ないと思うけど。というか、解決出来ないからTを作成する文法がないわけだけど。
 
 
クロージャーとか良いからこの辺何とかしてくれねーかな。


ちなみに、どーでもいいけど最近C言語とかの配列のint a[ ]的な
が後ろにあるのがどーも気持ち悪い。
実態は全然違うのに、まるでaはint型の変数みたいに見えるじゃん?今回みたいにJAVAなら[L ~型のオブジェクトだし。まぁ、気持ち悪いだけで、別に何の問題もないけど……

追記的なあれ書いておきました