2012-05-02 5 views
15

ジェネリッククラスを配列、さらにはプリミティブ配列にする必要があると指定しようとしています。これまでのところ、私が働いているのはこれです:Javaのジェネリックと配列型、あなたが考えているものではありません(ジェネリック型の配列など)

interface Foo<T> { 
    void process(T data); 
} 

public class Moo implements Foo<int[]> { 
    void process(int[] data) { 
    // do stuff here 
    } 
} 

これは完全に有効なJavaコードであり、プリミティブ配列はオブジェクトを拡張するために機能します。この質問はと全く異なるであり、私が探し続ける他のすべてのJava配列の一般的な質問と同じです。そのような状況では、人々はジェネリック型から配列を作成したいと考えています。

問題は、タイプTは、オブジェクトを拡張するものであればどれでもかまいません。私が欲しいのような何かをすることです:

<T extends ONLY ARRAYS> 

または

<T extends ONLY PRIMITIVE ARRAYS>. 

可能ということですか?

EDIT:最終目標は、渡される配列型のコンパイル時のチェックを追加することです。現在、古いオブジェクトは渡すことができ、うまくコンパイルできます。間違いは、クラスキャスト例外がスローされたときにのみ実行時に検出されます。コンパイル時の型チェックを強力にするために、これはJavaのGenericsの全般的なポイントです。

+2

の配列としてのタイプを返すために? – Jeffrey

+0

私は、「可能」であることに同意します。私の腸の感覚は、オブジェクトよりもプリミティブクラスの配列のスーパータイプが他にないことを示しています。 (クラスクラスにはisArray()があります) – esej

+0

異なるプリミティブ型のデータで画像を処理するための単一のインタフェースです。代替案は、それぞれのタイプに対して異なるインターフェースを用意することです。これは悪いクルージングです。例、Foo_S32、Foo_U8、Foo_F32、...など。 –

答えて

10

これはできません。クラスは配列を拡張することができないので、汎用パラメータT extends Object[]を満たす型は決してありません。 (。Object[]そのもの以外に、しかし、あなたはジェネリックを使用していないでしょう)

あなたは何ができるかは、このようなものです:

public interface Foo<T extends Number> { 
    public void process(T[] data); 
} 

しかし、その後、あなたはボクシングでのパフォーマンス上の問題に実行することがあります。

+4

String []などの特定の型の配列は、Object []に代入可能です。しかし、これはプリミティブ配列では役に立ちません。 –

+1

@StevenSchlansker私が与えた例はとにかくありませんでしたが、配列は型パラメータの束縛として使うことはできません。 – Jeffrey

+0

代替アプローチがパフォーマンスを殺すのは間違いありません。もう少し検索をした後、私が望む制約の種類を許す特別な言語例外を見つけることができません。あなたは正しい答えを最初に出したので、これを解決策として選択します。 –

1

できません。

Javaでは
public class SOTEST {  
    public static void main(String[] args) throws Exception { 
     int[] arr = new int[] {}; 
     Class c = arr.getClass(); 
     for(Class clazz:c.getInterfaces()) { 
      System.out.println(clazz.getName()); 
     } 

     System.out.println(c.getSuperclass().toString()); 
    } 
} 
8

、タイプパラメータがonlyサブタイプの関係によって制約、およびすべてのアレイareObjectClonableの唯一の共通スーパータイプとすることができる:いいえ「興味深い」インターフェースも、任意のスーパータイプが、オブジェクトは、プリミティブの配列のために存在しませんSerializable。あなたが得ることができる最も近い、非プリミティブコンポーネントタイプを持つすべての配列のスーパータイプである、Object[]に拘束し、または可能性Number[]に、Integer[]のスーパータイプである、Long[]することです...

Javaがなかった場合でも、そのような制約をサポートしていれば、その配列で何か役に立つでしょうか?配列要素に代入可能な式を書き留めることはできないため、結果を保持する変数を宣言することも、個別の要素を書き込むこともできないため、個々の要素を読み取ることはできません。あなたがTを知っT[]を参照することができますので、

interface Foo<T extends Whatever> { 
    void process(T[] data); 
} 

が、T extends Object[]を知ることは、直接あなたがすることはできません:私は、コンポーネントタイプではなく、配列型への型変数をバインドするだろう、と述べた

コンポーネントタイプを参照してください。

編集:あなたは間違いなく<T extends Whatever>を宣言する私のアドバイスに従うと配列型を参照するためにT[]を使用する必要がありますので、ジェフリーが正しくその配列型は、型の境界に使用することはできないと指摘、すなわち<T extends Whatever[]>は、コンパイルされません。

+0

制約を追加したいという要点は、一般化されたクラスが配列を操作して書くことはできず、APIを使いやすくするためです。現在のところ、コンパイル時チェックはなく、実行時にエラーが検出されるだけです。 –

-2

Xの配列には型階層がありません。 Integer []はNumber []のサブクラスではありません。

、あなたが望む結果を得るあなたのタイプパラメータTとして、配列のコンポーネント型を使用して、パラメータを宣言し、この操作を実行する必要があるのはなぜT.

+0

-1不正な情報の場合: 'Integer []' *は 'Number []'のサブタイプです。例えば、 'Number [] numbers = new Integer [] {1、2、3};'コンパイルはちょうどいい... – meriton

+0

これはナットで、java型システムの穴です。この \t整数[] ints =新しい整数[] {1、2、3}; \t Number [] numbers = ints; \t numbers [1] = new Float(4); \t(int x:ints){ \t \t System.out.println(x); \t} がコンパイルされ、実行時にArrayStoreExceptionがスローされます。 – PaulMurrayCbr

+1

はい、配列の共分散は、(配列の契約の一部としてArrayStoreExceptionsを扱わない限り、JLSのように)リスコフ置換可能性に違反します。ただし、ランタイムチェックでは、実行時にJavaが型保証された状態に保たれます。それが「ナット」であることは確かにあなたの意見を得ることができますが、タイプシステムの抜け穴にのみ焦点を当てることは、かなり制限された見解であると思います。配列は共変であり、実行時にチェックされます。 Genericsは各使用サイトで共変する必要があり、実行時にはチェックされません(実際にヒープの破損を有効にします)。どちらが優れたデザインですか? – meriton

関連する問題