2

問題:

厳密に型指定されたオブジェクトを返す汎用関数を作成したいと考えています。

関数 :

public <T > T GetPet(AnimalKingdom allAnimals,int id) {
    return (T) allAnimals.getAnimalsManager().findAnimalById(id);

}

上記の関数は、厳密に型指定されたオブジェクトを返すか、エラーをスローします。

使用法 :

GetPet<Tiger>(thisZoo,tigersId).Roar();

C# のバックグラウンドから来ています。同じことをグーグルで検索しましたが、解決策を見つけることができませんでした。機能させるには、ジェネリック型を関数に渡す必要があるようです。

上記のシナリオをJavaで実装するにはどうすればよいですか。

4

4 に答える 4

6

Java では、メソッド名の前にジェネリック メソッドの型引数を明示的に指定します。例えば:

class Example {
    public static <T> T getPet(AnimalKingdom allAnimals, int id) {
        return (T)allAnimals.getAnimalsManager().findAnimalById(id);
    }
}

次に、次のように呼び出します。

Example.<Tiger>getPet(thisZoo, tigersId).roar();

または、型推論を使用できます。

Tiger tiger = Example.getPet(thisZoo, tigersId);
tiger.roar();

ところで、getPet返されたオブジェクトが実際に のインスタンスであることを確認する実行時チェックが実行されないため、メソッドはあまり安全ではありませんTiger。実際、Java コンパイラは次の行で警告を出します。

return (T)allAnimals.getAnimalsManager().findAnimalById(id);

理由は、型の消去(T)により、へのキャストがチェックされていないためです。

コードを強化するために、次の変更をお勧めします。

class Example {
    public static <T> T getPet(Class<T> clazz, AnimalKingdom allAnimals, int id) {
        return clazz.cast(allAnimals.getAnimalsManager().findAnimalById(id));
    }
}

次に、次のように呼び出します。

Example.getPet(Tiger.class, thisZoo, tigersId).roar();

クラス オブジェクト ( Tiger.class) を渡す利点は次のとおりです。

  1. 使用する型をコンパイラに提供します<T>(これも型推論を介して)。
  2. メソッドを呼び出すことで、独自の明示的なランタイム タイプ チェックを追加できますClass.cast。Java コンパイラの警告がなくなり、タイプ セーフが復元されます。たとえば、findAnimalByIdTiger を期待していたときに Bear のインスタンスを誤って返した場合、ClassCastException.
于 2012-12-15T05:43:35.923 に答える
1

のようなものを試してください

Tiger tiger = GetPet(thisZoo,tigersId);
tiger.Roar();
于 2012-12-15T05:20:50.800 に答える
0

SylvainL が言ったように、ここではジェネリックは正しい選択ではありません。これは単純な継承/インターフェースの問題のように見えます。

新しい getPet メソッド:

public Animal getPet(AnimalKingdom allAnimals, int id)
{
    return allAnimals.getAnimalsManager().findAnimalById(id);
}

継承の使用:

class Animal { void Roar() { throw new Exception("This animal cannot roar!"); } };
class Tiger extends Animal { @Override void Roar() { ... }; ... };

使用法:

getPet(thisZoo, tigersId).Roar();

またはインターフェイスを使用する: (もう少し複雑ですが、おそらく一般的には優れています)

注: この場合、実際には Animal は必要ありません。Object を使用できます。

class Animal { ... }; // no Roar method
interface Roarer { void Roar(); };
class Tiger extends Animal implements Roarer { @Override void Roar() { ... }; ... };

注: 以下の使用方法のいずれかをメソッドに貼り付けて、最終的に次のようにすることができます。

roar(getPet(thisZoo, tigersId));

使用法: ( を削除できますがtry {} catch、これは一般的にはお勧めできません)

try
{
   ((Roarer)getPet(thisZoo, tigersId)).Roar();
}
catch (ClassCastException e) { /* handle error */ };

代替使用法: (安全に回避するためtry {} catchに、まだこれを試していませんが、うまくいくと思います)

Animal animal = getPet(thisZoo, tigersId);
if (Roarer.class.isAssignableFrom(animal.class))
   ((Roarer)animal).Roar();
else
   // handle error
于 2012-12-18T08:37:10.763 に答える
0

ここでジェネリックを使用することは、単に間違った選択です。継承、仮想関数、抽象クラス、およびインターフェイスを確認する必要があります。

于 2012-12-15T07:36:04.810 に答える