2017-03-24 3 views
11

をJavaのジェネリック型のエラーを解決し、私はJavaでこのような何かを達成したいと考えていますが、コンパイル時のエラーを取得:は抽象クラスメソッドで

The method onMessage(TextMessage, Class) in the type AbstractTestLoader is not applicable for the arguments (TextMessage, Class)

私はそのエラーの理由を理解し、私もそこにあるべき感じます鋳造でこれを達成するための何らかの方法、または他の方法でもよい。

public abstract class AbstractTestLoader<T extends AbstractEntity<T>> { 

    public void onMessage(TextMessage message) throws Exception { 
     onMessage(message, this.getClass()); // I want to correct this line in such a way so that I can call below method with actual Class of {T extends AbstractEntity<T>} 
    } 

    public void onMessage(TextMessage message, Class<T> clazz) throws Exception { 
     //here my original logic will go 
    } 
} 
+0

なぜあなたは*感じるのですか?おそらく、根本的な問題の理解を追加して、誰もが同じページにいるようにしたいと思うかもしれません。解決策の空間を探索する際の根本的な原因に同意する必要があります。 – GhostCat

+0

こんにちは@GhostCat、私は既にコメント行で私の根底にある問題を探そうとしました '私はこのような方法でこの行を修正して、{T extends AbstractEntity }クラスのメソッドを呼び出すことができます。私が投稿した解決策を参考にして、より良い解決策を提案してください。 –

+0

'AbstractTestLoader'はダイレクトスーパークラスですか? – glee8e

答えて

4

最後に、2,3回試してみたところ、私は単純で実用的な解決策を手に入れましたが、可能な限り他の回答も聞いています。ありがとう

public abstract class AbstractTestLoader<T extends AbstractEntity<T>> { 

    abstract Class<T> getEntityType(); 

    public void onMessage(TextMessage message) throws Exception { 
     onMessage(message, getEntityType()); 
    } 

    public void onMessage(TextMessage message, Class<T> clazz) throws Exception { 
     //here my original logic will go 
    } 
} 
2

Java implements generics via type erasureこれは単なるコンパイル時の概念であることを意味します。プログラムが実行されているときは、AbstractTestLoader<Foo>AbstractTestLoader<Bar>の間に違いはありません。

コンパイル時にTの型を認識しているクラスを作成して、実際のクラスタイプを提供できる、いくつかの回避策があります。しかし、ジェネリック型が実行時に何であるかを発見するために純粋なジェネリックを使用する方法はありません。

+0

実際には方法があります。@ glee8eの答え –

+0

@FedericoPeraltaSchaffnerを参照してくれてありがとうございます。しかし、@マークはシステム通知を私に送りません。なぜなら、後ろの '' s'はあなたに 'glee8e's'という名前の人を呼んでいると思うからです。ちょっとリマインダ:) – glee8e

+0

@FedericoPeraltaSchaffner:glee8eの答えは良いもので、多くの場合うまくいくでしょう。私はそれが私の答えを無効にするとは思わない:私の心の中で私が言及した回避策の1つとして "コンパイル時に' T 'の型を認識しているクラスが実際のクラス型" Vishalの答えでは、これは抽象的な方法で行います。 glee8eの場合は、消費するクラスを特定の方法で宣言する必要があります。 – StriplingWarrior

5

Javaジェネリックは実行時に消去されますが、クラスファイルにJavaジェネリックが含まれていれば、リフレクションAPIは取得できません。ここで

は、これらの仮定と迅速なソリューションです:

  1. AbstractTestLoaderは直接のスーパークラスです。
  2. サブクラスは、スーパークラスを宣言するときに型ワイルドカードを使用しません。このようなサブクラスはclass GenericLoader<T extends SubclassAbstractEntity<T>> extends AbstractTestLoader<T>は存在しません。ここ

コードである:

public class AbstractTestLoader<T extends AbstractEntity<T>> { 

    private static final ClassValue<Class<?>> TYPE_PARAMETER_CACHE = new ClassValue<Class<?>>() { 
     @Override 
     protected Class<?> computeValue(Class<?> type) { 
      assert AbstractTestLoader.class.isAssignableFrom(type); 
      assert type.getSuperclass() == AbstractTestLoader.class; 
      Type genericSuperclass = type.getGenericSuperclass(); 
      assert genericSuperclass instanceof ParameterizedType; 
      Type entityType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; 
      assert entityType instanceof Class<?>; 
      return (Class<?>) entityType; 
     } 
    }; 

    @SuppressWarnings("unchecked") 
    protected Class<T> getEntityType() { 
     return (Class<T>) TYPE_PARAMETER_CACHE.get(this.getClass()); 
    } 

    public void onMessage(Object message) throws Exception { 
     onMessage(message, getEntityType()); // getting compile time error here 
    } 

    public void onMessage(Object message, Class<T> clazz) throws Exception { 
     //here my original logic will go 
    } 
} 

getEntityTypeは、これら2つの仮定が失敗サブクラスにオーバーライドすることができます。

関連する問題