2012-03-25 9 views
4

私は同様の問題がいくつかのスレッドについて議論されていることは知っていますが、私はまだ私の問題の解決策を見つけることができません。Javaジェネリックは、コマンドラインからではなく、Eclipseでコンパイルされます。

他のスレッド: Compilers behave differently with a null parameter of a generic method

Java generics code compiles in eclipse but not in command line

だから私はイベントとイベント・ハンドラ・インタフェースのためのジェネリックを使用してイベント・メカニズムを書いていました。コマンドラインjavacではエラーを生成するが、eclipse indigoではエラーを生成しないイベントを登録するためのコードは次のとおりです。以下のコードでは、EventRegistryは、イベントのクラス名と文字列形式のイベントハンドラをキャプチャします。

私はいくつかの他のクラスでは...以下のインタフェース

public interface Event{} 
public interface EventHandler<T extends Event> {} 

私のEventManagerクラスのメソッド

public <T extends Event, P extends EventHandler<T>> void registerManagedHandler(EventRegistry er, ClassLoader cl) throws ClassNotFoundException 
    { 
       ... 

       Class<T> eventClass = (Class<T>) cl.loadClass(er.getEventClass()); 
       Class<P> eventHandlerClass = (Class<P>) cl.loadClass(er.getEventHandlerClass()); 

     ... 
     register(eventHandlerClass, eventClass); 
    } 

private <T extends Event, P extends EventHandler<T>> void register(Class<P> handler, Class<T> eventClass) 
    { 
     ... 
    } 

を作成しました。私には声明があります。

EventManager.getInstance().registerManagedHandler(er,al); 

Eclipseは正しくコードをコンパイルが、同じエラーが発生しunregistering/enabling/disablingイベントのための同様の方法があり

incompatible types; inferred type argument(s) com.mycompany.events.Event,java.lang.Object do not conform to bounds of type variable(s) T,P 
    [javac] found : <T,P>void 
    [javac] required: void 
    [javac]        EventManager.getInstance().registerManagedHandler(er,al); 

コマンドライン上のjavacからコンパイル中にエラーが発生しました。上記のコードから 私は型制約を取り除く(<T extends Event, P extends EventHandler<T>>) registerManagedHandlerから試してみましたが、その後登録(...)メソッドの呼び出しでエラーが発生した

私の修正registeredManagedHandler()..

public void registerManagedHandler(EventRegistry er, ClassLoader cl) throws ClassNotFoundException 
    { 
         ... 
      Class<? extends Event> eventClass = (Class<? extends Event>) cl.loadClass(er.getEventClass()); 
      Class<? extends EventHandler<? extends Event>> eventHandlerClass = (Class<? extends EventHandler<? extends Event>>) cl.loadClass(er.getEventHandlerClass()); 
      ... 
     register(eventHandlerClass, eventClass); 

    } 

新で時エラーをコンパイル生成日食も。

Bound mismatch: The generic method register(Class<P>, Class<T>) of type EventManager is not applicable for the arguments 
(Class<capture#20-of ? extends EventHandler<? extends Event>>, Class<capture#22-of ? extends Event>). The inferred type 
capture#20-of ? extends EventHandler<? extends Event> is not a valid substitute for the bounded parameter <P extends 
EventHandler<T>> 

私はregister(...)メソッドから型チェックを削除するつもりはありません。

ご理解のためにコードの詳細が必要な場合はお知らせください。

このような問題や回避策を適切に処理する方法を教えてください。私はジェネリックスにはかなり新しいですが、これを実装する前に基本的なガイドを読んでいます。

また、自分のコンパイラではなく私のUbuntuシステムにインストールされているsun-javac6をeclipseに強制する方法が見つかりませんでした。私はEclipse(プロジェクト - >プロパティ - > Javaビルドパス - >ライブラリ)でJREを変更する方法を知っていますが

ありがとうございます。

更新:ご返信ありがとうございます。もっと情報を提供できるかどうか教えてください。私のEclipseバージョンはIndigo(3.7)

です。ここはsscceです。 Eclipseでプログラムを実行すると、うまく動作します(コンパイルと実行)。しかし、コマンドラインでjavac GenericTester.javaを実行すると、次のエラーが発生します。私はsscce.orgのコンパイラツールでこれを確認しました。私がインストールされているJavaの程度

[email protected]:~/mywork/GenericTest/src$ javac GenericTester.java 

GenericTester.java:40: incompatible types; inferred type argument(s) Event,java.lang.Object do not conform to bounds of type variable(s) T,P 
found : <T,P>void 
required: void 
      new EventManager().registerEvent(er); 
              ^
Note: GenericTester.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 
1 error 

いくつかのより多くの情報:私は実行するコマンドを含むコマンドラインから

interface Event { 
} 

interface EventHandler<T extends Event> { 
} 

class EventRegistry { 
    public String eventClass; 
    public String eventHandlerClass; 
} 

class EventManager { 
    public <T extends Event, P extends EventHandler<T>> void registerEvent(
      Class<T> eventClass, Class<P> eventHandlerClass) { 
    } 

    public <T extends Event, P extends EventHandler<T>> void registerEvent(
      EventRegistry er) throws ClassNotFoundException { 
     Class<T> eventClass = (Class<T>) this.getClass() 
       .getClassLoader().loadClass(er.eventClass); 
     Class<P> eventHandlerClass = (Class<P>) this 
       .getClass().getClassLoader() 
       .loadClass(er.eventHandlerClass); 
     registerEvent(eventClass, eventHandlerClass); 
    } 
} 

class MyEvent implements Event { 
} 

class MyEventHandler implements EventHandler<MyEvent> { 
} 

public class GenericTester { 
    public static void main(String[] args) { 
     EventRegistry er = new EventRegistry(); 
     er.eventClass = MyEvent.class.getName(); 
     er.eventHandlerClass = MyEventHandler.class.getName(); 
     try { 
      new EventManager().registerEvent(er); 
      System.out.println("It worked."); 
     } catch (ClassNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

エラー。

[email protected]:~/mywork/GenericTest/src$ java -version 
java version "1.6.0_30" 
Java(TM) SE Runtime Environment (build 1.6.0_30-b12) 
Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode) 

[email protected]:~/mywork/GenericTest/src$ javac -version 
javac 1.6.0_30 
+1

に固定されたJava 5およびJava 6のバグです。第1の「?あなたの質問の下で私の質問を聞いてきます。あなたの質問は "なぜSDKとEclipseコンパイラの動作の違い?"です。もしそうなら、それを編集として追加して質問をすることをお勧めします。 –

+0

@Nitrajコマンドラインで使用されているJDKが、Eclipseでコンパイルに使用されているものと同じであることを確認してください。使用しているコマンドラインを質問に追加できますか? –

+0

コンパイルエラーを再現するために、5つのコードスニペットにまたがる不完全なソースコードを移動するのは本当に難しいです。私たちがあなたを助けてくれるようにするには、SSCCEを掲示してください。ヒント:デフォルトの可視性(つまりパブリックではない)で型を宣言すると、それらはすべて同じソースファイルに入ることができ、コードをeclipseにインポートするのがずっと簡単になります。 – meriton

答えて

0

私はあなたの最初の質問に答えるのに十分な詳細はないと思います。 > Javaの - - しかし、あなたの2番目の質問のために、あなたは設定使用してJavaランタイム環境を構成することができます>インストール済みのJREを、あなたは環境使ってJavaコンパイラ準拠レベルを設定することができます - > Javaの - >コンパイラ

enter image description here

0

JDK 1.6がそのSSCCEをコンパイルすることを拒否した理由はで説明されています。Java 7ではCompilers behave differently with a null parameter of a generic method

、パラメータの型や戻り値には表示されません種類の変数の推論アルゴリズムはへextendedました型パラメータの境界を考慮に入れてください。実際に、SSCCEはJDK 1.7.0_02のjavacで正常にコンパイルされます。

私はあなたのregisterEventジェネリックスを誤用していると思います:メソッドの型パラメータは呼び出し元によって(通常は型推論アルゴリズムによって指定されますが、明示的にしか指定できません)、実際の呼び出し側の型引数はEventRegistry型の引数と一致しますが、コンパイラによってチェックされません。考えてみましょう:

er.eventHandlerClass = "java.lang.String"; 
    new EventManager().<MyEvent, MyEventHandler>registerEvent(er); 

コンパイルと実行は正常ですが、実際にイベントが発生したときにClassCastExceptionが発生する可能性があります。そのため、クラスをStringとして渡すことはお勧めしません。 Stringを購読しようとしている実装に

public void registerEvent(EventRegistry er) throws ClassNotFoundException { 
    Class<? extends Event> eventClass = this.getClass() 
      .getClassLoader().loadClass(er.eventClass) 
      .asSubclass(Event.class); 
    Class<? extends EventHandler> eventHandlerClass = this 
      .getClass().getClassLoader() 
      .loadClass(er.eventHandlerClass) 
      .asSubclass(EventHandler.class); 
    registerEvent(eventClass, eventHandlerClass); 
} 

、:

あなたが本当に彼らがクラスローダと空想を取得するための文字列にする必要がある場合、あなたは少なくともクラスは、適切なタイプを実装することを確認する必要がありますEventHandlerClassCastExceptionになります。

コンパイラの警告は、私は、呼び出し元がまだやることができ、EventHandlerは右のタイプのパラメータを持っていることを確認していないという事実のために私たちに警告してこのコードは、まだ完璧ではない:

er.eventClass = Event.class.getName(); 
    er.eventHandlerClass = MyEventHandler.class.getName(); 
    new EventManager().registerEvent(er); 

でもはすべてEventで処理できません。ただし、タイプ消去のため、EventHandlerのイベントタイプを確認することは一般的に不可能です。

関連する問題