2009-04-25 15 views
6

私はいくつかのコードkatasで遊んでいると同時に、Javaジェネリックスをよりよく理解しようとしています。私は、私がそれらを見るのが好きなように配列を出力するこの小さなメソッドを持っています。そして、私は、物の配列とインデックスを受け入れ、インデックスの上または下の '物'の配列を返しますバイナリ検索アルゴリズムです)。javaの汎用メソッドにint配列を渡すことはできますか?

二つの質問、

#1 iはsplitBottomとsplitTopでTへのキャストを避けることはできますか?それは正しい気がしません、または私は間違った方法(私はPythonや何かを使用するように教えていない..)に行く))

#2私はプリミティブまたはより良い解決策がありますか?

public class Util { 

    public static <T> void print(T[] array) { 
     System.out.print("{"); 
     for (int i = 0; i < array.length; i++) { 
      System.out.print(array[i]); 
      if (i < array.length - 1) { 
       System.out.print(", "); 
      } 
     } 
     System.out.println("}"); 
    } 

    public static <T> T[] splitTop(T[] array, int index) { 
     Object[] result = new Object[array.length - index - 1]; 
     System.arraycopy(array, index + 1, result, 0, result.length); 
     return (T[]) result; 
    } 

    public static <T> T[] splitBottom(T[] array, int index) { 
     Object[] result = new Object[index]; 
     System.arraycopy(array, 0, result, 0, index); 
     return (T[]) result; 
    } 

    public static void main(String[] args) { 

     Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     print(integerArray); 
     print(splitBottom(integerArray, 3)); 
     print(splitTop(integerArray, 3)); 

     String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}; 
     print(stringArray); 
     print(splitBottom(stringArray, 3)); 
     print(splitTop(stringArray, 3)); 

     int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     // ??? 
    } 
} 

答えて

9

ジェネリックスは、一貫した方法でプリミティブを処理しません。これは、GenericsはC++のテンプレートと似ていないため、単一のクラスにコンパイル時の追加に過ぎません。

genericがコンパイルされると、上の例でObject []が実装タイプとして終了します。 int []とbyte []などのように、Object []を拡張しないでください。たとえ関連するコードが同じであってもそれらを相互に変更することはできません。(ジェネリックはテンプレートではありません)

唯一のクラスint []とObject [] shareはObjectです。上記のメソッドのObjectを型として記述できます(System.arraycopy、Array.getLength、Array.get、Array.setを参照)

1

質問1: キャスト配列は期待どおりに動作しません。 StringはObjectですが、String配列はObject配列ではありません。

public static <T> T[] splitTop(T[] array, int index) { 
    T[] result = Arrays.copyOfRange(array, index + 1, array.length); 
    return result; 
} 

質問2: プリミティブの配列では、私の機能が明らかにどちらか動作しません

のようなものを使用してみてください。それに対してエレガントな解決法はありません。たとえば、基本配列型ごとに本質的に同じメソッドのいくつかのコピーを持つ配列ライブラリを見てください。

+0

ジェネリックではできません。その結果、互換性のない型エラーが発生します。 – hbw

+0

@htwもっと説明できますか? – blank

3

1 splitBottomとsplitTopのTへのキャストを避けることはできますか? 、)

だけでなく、あなたはそれを避けることはできません。それは は右に感じる、または私はこの についてつもり間違った方法はありません( のpythonか何かを使用するように私に教えていません。)しかし、あなたはそれをするべきではありません。 Javaでは、異なるタイプの配列は実際には異なるランタイム型です。 Object[]として作成された配列は、AnythingElse []の変数に割り当てることはできません。ジェネリックでは型Tは消去されますが、後であなたが約束したとおりにコードを使用しようとするとClassCastExceptionがスローされますが、そうではありません。

Java 6以降ではArrays.copyOf...メソッドを使用するか、以前のバージョンのJavaを使用している場合はReflectionを使用して正しいタイプの配列を作成します。たとえば、

T [] result =(T [])Array.newInstance(array.getClass()。getComponentType()、size);

2プリミティブ配列を処理するために別個のメソッドを記述する必要がありますか? より良い解決策がありますか?

おそらく別の方法を記述することをお勧めします。 Javaでは、プリミティブ型の配列は参照型の配列とは完全に別です。両方とも一緒に働く良い方法はありません。

Reflectionを使用して、両方を同時に処理することは可能です。リフレクションは、プリミティブ配列とリファレンス配列で同様に動作するArray.get()Array.set()メソッドを持っています。ただし、プリミティブ配列と参照配列の両方の唯一のスーパータイプがObjectであるため、これを実行すると型の安全性が失われます。

1

Javaでは、タイプセーフな方法で汎用配列を構築することはできません。代わりにジェネリックシーケンスタイプを使用してください(たとえば、java.util.Listなど)。ここで

は、私は汎用コンテナクラスfj.data.Streamを使用して、あなたのテストプログラムを記述します方法は次のとおりです。

import fj.data.Stream; 
import static fj.data.Stream.range; 

// ... 

public int[] intArray(Stream<Integer> s) { 
    return s.toArray(Integer.class).array() 
} 

public static void main(String[] args) { 
    Stream<Integer> integerStream = range(1, 10); 
    print(intArray(integerStream)); 
    print(intArray(integerStream.take(3))); 
    print(intArray(integerStream.drop(3))); 

    // ... 
} 
0

あなたが達成しようとしているものには二つの問題を持っています。

まず、Objectから実際に継承されないプリミティブ型を使用しようとしています。これは事を台無しにするでしょう。実際にこれを行う必要がある場合は、intなどではなくIntegerを明示的に使用してください。

第2の大きな問題は、Javaジェネリックスにタイプ消去があることです。つまり、実行時には、実際にジェネリックのタイプを参照することはできません。これはジェネリックサポートと非ジェネリックサポートコードを混在させるために行われ、Java開発者の頭痛の主な原因であるIMHOと、ジェネリック医薬品が1日目からJavaに移行したはずのもう一つの証拠となりました。それについてのtutorialの部分を読んで、それはこの問題をより明確にするでしょう。

0

おそらく、プリミティブを対応するコレクションにラップする必要があります。

また、プリミティブコレクションを徹底的に調べることをお勧めします(http://trove.starlight-systems.com)。これはジェネリックの質問とは無関係ですが、かなり興味深いかもしれません。

関連する問題