3

次の短い自己完結型のコードがあり、コンパイル時にエラーが表示されます。私は必死にそれをコンパイルさせようとしました。私は通常、ジェネリック医薬品に問題はありませんが、これをあきらめて、チームの助けを求めます。

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class CacheWithGenericsDoesNotCompile {

  // Class definition can't be modified
  static class Resource<T extends Resource<T>> {}

  // Class definition can't be modified
  static class ResourceType<T extends Resource<T>> {
    public ResourceType(Class<T> type) {}
  }

  // Variable definition may be modified
  static LoadingCache<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>> cache = CacheBuilder.newBuilder().build(
      new CacheLoader<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>>() {
        @Override public ResourceType<? extends Resource<?>> load(Class<? extends Resource<?>> key) throws Exception {
          return new ResourceType<? extends Resource<?>>(key);
        }
    });

  // Method definition can't be modified, method content may.
  @SuppressWarnings("unchecked")
  static <T extends Resource<T>> ResourceType<T> getResourceType(Class<T> type) {
    return (ResourceType<T>)cache.getUnchecked(type);
  }
}

コンパイルに失敗する行は次のとおりです。

return new ResourceType<? extends Resource<?>>(key);

失敗する理由はわかっています。new Xxxx<...>疑問符(?)を付けて書くことはできません。この行を別の方法で記述して、他の行をコンパイルすることはできません。

ジェネリックがない場合のフォールバックソリューションがありResourceますが、可能な限りジェネリックを維持したいと思いResourceます。

LoadingCacheのように呼び出す必要があることを除いて、ジェネリックについての制限はありませんgetResourceType(Class)

だから...どうすればこのコードを修正できますか?

4

3 に答える 3

5

警告を無視した解決策:

  static LoadingCache<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>> cache = CacheBuilder.newBuilder().build(
      new CacheLoader<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>>() {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override public ResourceType<? extends Resource<?>> load(Class<? extends Resource<?>> key) throws Exception {
          return new ResourceType(key);
        }
    });

コメントで@JohnBによって提案されたよう に。このコードは、型消去のため、実行時に問題のコードと同じです。

于 2013-03-13T10:34:27.827 に答える
1

私はゴンタードの解決策(これに賛成する場合は、ゴンタードの答えにも賛成するようにしてください)とミリムースのコメントでもう少し遊んだ。私は、はるかに読みやすいコードのために、ジェネリックを完全に削除するこのソリューションに到達しました。

@SuppressWarnings("rawtypes")
static LoadingCache<Class, ResourceType> cache = CacheBuilder.newBuilder().build(
    new CacheLoader<Class, ResourceType>() {
      @SuppressWarnings("unchecked")
      @Override public ResourceType load(Class key) throws Exception {
        return new ResourceType(key);
      }
  });
于 2013-03-13T14:09:19.480 に答える
0

key適切なタイプにキャストできれば

Class<T> for some T that T<:Resource<T>

その後、私たちは書くのに問題はありません

ResourceType<? extends Resource<?>> result = new ResourceType<>(casted_key)

通常、この種のキャストはワイルドカードキャプチャを介して実行できますが、型変数に自己参照の境界がある場合は機能しません。Generics and Class <?の回避策を参照してください。Enum <?>>、EnumSet.allOf(class)vs class.getEnumConstants()を拡張します

于 2013-03-13T15:14:05.310 に答える