71

私はGWT用のGXTコードをいくつか見ていて、Javaチュートリアルで別の例を見つけることができないジェネリックスのこの使用法に出くわしました。クラス名はcom.extjs.gxt.ui.client.data.BaseModelData、すべてのコードを確認する場合に使用します。重要な部分は次のとおりです。

private RpcMap map;

public <X> X get(String property) {
  if (allowNestedValues && NestedModelUtil.isNestedProperty(property)) {
    return (X)NestedModelUtil.getNestedValue(this, property);
  }
  return map == null ? null : (X) map.get(property);
}

Xはクラス内または階層内のどこにも定義されておらず、eclipseで「gotodeclaration」を押すと<X>パブリックメソッドシグネチャのinに移動します。

次の2つの例を使用してこのメ​​ソッドを呼び出して、何が起こるかを確認しました。

public Date getExpiredate() {
    return  get("expiredate");
}

public String getSubject() {
    return  get("subject");
}

それらはコンパイルされ、エラーや警告は表示されません。少なくとも、これを機能させるにはキャストを行う必要があると思います。

これは、ジェネリックスが何でもかまいませんが、実行時に爆発する魔法の戻り値を許可することを意味しますか?これは、ジェネリックスが行うことになっていることに反しているようです。誰かが私にこれを説明し、おそらくこれをもう少しよく説明するいくつかのドキュメントへのリンクを教えてもらえますか?ジェネリックスに関するSunの23ページのPDFを確認しましたが、戻り値のすべての例は、クラスレベルで定義されているか、渡されたパラメーターの1つに含まれています。

4

6 に答える 6

57

このメソッドは、期待するタイプを返します(<X>メソッドで定義され、完全に制限されていません)。

戻りタイプが実際に戻り値と一致するという規定がないため、これは非常に危険です。

これが持つ唯一の利点は、任意の型を返すことができるそのような汎用ルックアップメソッドの戻り値をキャストする必要がないことです。

私は言います:あなたはほとんどすべての型安全性を失い、あなたがへの各呼び出しで明示的なキャストを書く必要がないということだけを得るので、そのような構造を注意して使用してくださいget()

そしてそうです:これは実行時に爆発し、ジェネリックが何を達成すべきかという考え全体を壊す黒魔術です。

于 2008-12-03T22:05:41.700 に答える
40

タイプはメソッドで宣言されます。それが「<X>」という意味です。タイプのスコープはメソッドのみであり、特定の呼び出しに関連しています。テストコードがコンパイルされる理由は、コンパイラがタイプを判別しようとし、それができない場合にのみ文句を言うためです。明示的にしなければならない場合があります。

たとえば、の宣言Collections.emptySet()

public static final <T> Set<T> emptySet()

この場合、コンパイラは次のことを推測できます。

Set<String> s = Collections.emptySet();

ただし、それができない場合は、次のように入力する必要があります。

Collections.<String>emptySet();
于 2008-12-03T22:02:53.643 に答える
5

GXTクラスで同じことを理解しようとしていました。具体的には、次のシグネチャを持つメソッドを呼び出そうとしていました。

class Model {
    public <X> X get(String property) { ... }
}

コードから上記のメソッドを呼び出して、Xを文字列にキャストさせるには、次のようにします。

public String myMethod(Data data) {
    Model model = new Model(data);
    return model.<String>get("status");
}

上記のコードはgetメソッドを呼び出し、Xによって返される型を文字列として返す必要があることを通知します。

メソッドがあなたと同じクラスにある場合、私はそれを「this」で呼び出さなければならないことに気づきました。例えば:

this.<String>get("status");

他の人が言っているように、これはGXTチームによってかなりずさんで危険です。

于 2011-09-27T14:38:59.480 に答える
2

RpcMap(GXT API 1.2)からの興味深いメモ

getのヘッダー:

public java.lang.Object get(java.lang.Object key)

そこにインスタンス化されていないジェネリックパラメータが<X>あると、あちこちで「オブジェクト」と言う必要がないことを除いて、同じ効果があります。私は他のポスターに同意します、これはずさんで少し危険です。

于 2008-12-03T22:05:02.607 に答える
2

BaseModelData は、安全ではないため、コンパイル時に unchecked 警告を発生させます。このように使用すると、コード自体に警告がなくても、実行時に ClassCastException がスローされます。

public String getExpireDate() {
  return  get("expiredate");
}
于 2008-12-03T22:17:24.003 に答える
0

はい、これは危険です。通常、このコードは次のように保護します。

<X> getProperty(String name, Class<X> clazz) {
   X foo = (X) whatever(name);
   assert clazz.isAssignableFrom(foo);
   return foo;
}

String getString(String name) {
  return getProperty(name, String.class);
}

int getInt(String name) {
  return getProperty(name, Integer.class);
}
于 2009-02-21T13:02:00.510 に答える