web-dev-qa-db-ja.com

JavaジェネリックはC ++テンプレートとどのように違いますか?なぜパラメーターとしてintを使用できないのですか?

作成しようとしています

ArrayList<int> myList = new ArrayList<int>();

in Javaしかしそれは機能しません。

型パラメーターとしてintが機能しない理由を誰かが説明できますか?
Integerプリミティブにintクラスを使用すると、intが受け入れられない理由を説明できますか?

Javaバージョン1.6

50
yesraaj

JavaジェネリックはC++テンプレートとは非常に異なるため、ここでは違いをリストしようとはしません。 (詳細については、 C++とJavaの「ジェネリック」型の違いは何ですか? を参照してください。)

この特定の場合、問題はプリミティブをジェネリック型パラメーターとして使用できないことです( JLS§4.5.1 :「型引数は参照型またはワイルドカードのいずれかです。」を参照)。

ただし、オートボクシングにより、次のようなことができます。

List<Integer> ints = new ArrayList<Integer>();
ints.add(3); // 3 is autoboxed into Integer.valueOf(3)

それで痛みの一部が取り除かれます。ただし、実行時の効率は間違いなく低下します。

64
Michael Myers

Intが機能しないのは、プリミティブ型をJavaの汎用パラメーターとして使用できないためです。

あなたの実際の質問については、C++テンプレートはJavaジェネリックとどのように違いますか、答えは...本当に本当に異なります。本質的に2つの完全に異なるアプローチ同様のエンドエフェクト。

Javaは、ジェネリックの定義に集中する傾向があります。つまり、ジェネリック定義の有効性は、ジェネリックのコードのみを考慮してチェックされます。パラメータが適切に制約されていない場合、特定のアクションを実行できません。最終的に呼び出される実際のタイプは考慮されません。

C++は逆です。テンプレート自体では最小限の検証のみが行われます。本当に有効であると見なされるためには、構文解析可能であれば十分です。定義の実際の正確性は、テンプレートが使用される場所で行われます。

25
JaredPar

これらは非常に異なる概念であり、同じタスクのすべてではなく一部を実行するために使用できます。他の回答で述べたように、すべての違いを検討するにはかなりの時間がかかりますが、ここでは大まかなストロークと考えています。

ジェネリックは、ジェネリックコンテナの単一のインスタンス化により、ランタイムポリモーフィックコンテナを可能にします。 Javaでは、すべての(非プリミティブ)オブジェクトは参照であり、すべての参照は同じサイズ(および同じインターフェイスの一部)であるため、バイトコードで処理できます。ただし、バイトコードのインスタンス化のみが必要な意味は、タイプ消しゴムです。コンテナがインスタンス化されたクラスを知ることはできません。これは、オブジェクトが常に参照されるとは限らない根本的に異なるオブジェクトモデルのために、c ++では機能しません。

テンプレートは、複数のインスタンス化を通じてコン​​パイル時のポリモーフィックコンテナを可能にします(c ++型システム上で(現在弱い型付けの)言語を提供することにより、テンプレートのメタプログラミングも可能にします)。これにより、特定の型の特殊化が可能になります。欠点は、複数のコンパイルされたインスタンス化が必要になることによる潜在的な「コードの膨張」です。

テンプレートはジェネリックよりも強力です。前者は実質的にc ++に埋め込まれた別の言語ですが、私の知る限り、後者はコンテナでのみ有用です

9
Todd Gardner

主な違いは実装方法にありますが、名前は実装を正確に説明しています。

テンプレートはテンプレートのように動作します。だから、あなたが書くなら:

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f(x);
...

コンパイラはテンプレートを適用するため、最終的にコンパイラは次のようにコードを扱います。

void f_generated_with_int(int s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f_generated_with_int(x);
...

したがって、fの呼び出しに使用される各タイプに対して、新しいコードが「生成」されます。

一方、ジェネリックは型チェックされるだけですが、その後すべての型情報が消去されます。だから、あなたが書くなら:

class X<T> {
    private T x;

    public T getX() { return x; }
    public void setX(T x) { this.x = x; }
}

...
Foo foo = new Foo();
X<Foo> x = new X<>();
x.setX(foo);
foo = x.getX();
...

Javaは次のようにコンパイルします。

class X {
    private Object x;

    public Object getX() { return x; }
    public void setX(Object x) { this.x = x; }
}

...
Foo foo = new Foo();
X x = new X();
x.setX(foo);
foo = (Foo)x.getX();
...

最終的には:

  • テンプレートは、テンプレート化された関数の各呼び出しのインスタンス化を必要とします(各.cppファイルのコンパイル)。したがって、テンプレートのコンパイルは遅くなります。
  • ジェネリックでは、Objectではないため、プリミティブを使用できません。したがって、ジェネリックは汎用性が低くなります。
8
kravemir

Javaでは、プリミティブを型パラメーターとして使用できません。型の消去によるJavaのジェネリックは、定義したとおりに型を使用していることをコンパイラがチェックすることを意味しますが、コンパイル時にはすべてがオブジェクトとして扱われます。 intおよびその他のプリミティブはオブジェクトではないため、使用できません。代わりに、整数を使用してください。

3
Pesto

これは、intがプリミティブであり、 既知の問題 であるためです。

本当にしたい場合は、それを行うことができる独自のコレクションをサブクラス化/作成することができます。

3
z -

GNU int値のArrayListのように動作するTroveからTIntArraListを試すことができます。

1
Peter Lawrey