9

C ++では、次のようなパラメーターで関数の戻り型を指定できます。

C ++

    float* myFloat = CollectionClass.ptr<float>();
    int*   myInt   = CollectionClass.ptr<int>();

追加のクラス引数を追加せずに戻り型を指定するのに相当するものはJavaにありますか?

Java

    //This doesn't work (due to type erasure) 
    public <T> T getDate() 
    {
        if (T instanceof Date)
            return new Date();
        if (T instanceof Calendar)
            return new Calendar();
    }

    Date myDate = getDate<Date>();
4

3 に答える 3

19

シグニチャを使用してメソッドを宣言することはまったく問題ありませんpublic <T> T getDate()

ただし、必要なものを返すメソッドを実装することはできません。メソッドが実行時に行うことは、型パラメーターを知らないため、型パラメーターだけに依存することはできません。

これを直感的に理解するには、ジェネリックで記述されたコードは、ジェネリックパラメーターを削除し、必要に応じてキャストを挿入するだけで、ジェネリックを使用せずに同等に記述できることを理解してください。これが「型消去」の意味です。

したがって、ジェネリックスであなたの方法が可能かどうかを確認するには、ジェネリックスなしでどのようにそれを行うかを尋ねてください。

public Object getDate() 
{
    // what would you do here?
}

Date myDate = (Date)getDate();

ジェネリックスなしでそれを行うことができない場合は、ジェネリックスでもそれを行うことはできません。

C++テンプレートは完全に異なります。テンプレート化された関数とクラスの場合、C ++テンプレートは、使用される型引数ごとに関数またはクラスの「個別のコピー」を生成します。つまり、コンパイラはテンプレート化されたコードを取得し、それを複数のバージョンに「コピーして貼り付け」ます。したがって、コードの各コピーは特定の型引数に固有であり、実行時にその型を使用できます。

これが、C++テンプレートコードを使用するためにソース形式で利用可能である必要がある理由です。「コンパイルされた」テンプレートなどはありません。ただし、Javaでは、コンパイルされたジェネリッククラスを使用できます。Javaのジェネリッククラスとメソッドは、それらが使用できるタイプについては何も想定していません。

于 2013-02-27T20:09:52.260 に答える
10

さて、コードが条件付きであることを明確にするための編集を行いTます...

いいえ、Java内でこれを機能させるのは簡単なことではありません。質問にあるように、型消去が原因です。あなたは渡すことができますClass<T>

public <T> T getDate(Class<T> clazz)
{
    // Now use clazz to work out what to do
}

...しかし、実行時のそれ自体の「値」に依存することは何もできません。Tそれは単に知られていないからです。ジェネリックスは、残念ながらJavaではやや貧血です:(


編集:コードを条件付きにするための編集の前にT..。

type引数を別の方法で指定するだけです。

import java.util.Date;

class Test {

    public static <T> T getDate() {
        return (T) new Date();
    }

    public <T> T getDateInstanceMethod() {
        return (T) new Date();
    }

    public static void main (String [] args) {
        Date date = Test.<Date>getDate();

        // Compiles fine, but is obviously bogus.
        String string = Test.<String>getDate();

        // And specifying a type argument for an instance method
        Test test = new Test();
        date = test.<Date>getDate();
    }
}

私はいつも「通常の引数の直前に型引数を置く」アプローチを好みましたが、そこに行きます...

編集:rgettmanが指摘しているように、ここでは型推論がとにかく正しいことを行うので、多くの場合、実際に型引数を指定する必要はありません。時々あなたはそうします。

于 2013-02-27T17:25:07.090 に答える
1

を使用Arrays.asListすると、リターンタイプを指定する必要がある場合があります。Javaは、すべての引数に共通のスーパータイプに基づいて戻り型を「絞り込み」ようとしますが、特定の型が必要になる場合があります。例えば、

List<Number> list = Arrays.asList(1, 2, 3);

ここで、をArrays.asList返すList<Integer>と、コンパイラエラーが発生します。を返すようにするにList<Number>は、ジェネリック型を指定する必要があります。

List<Number> list = Arrays.<Number>asList(1, 2, 3);
于 2013-02-27T17:36:04.917 に答える