2012-03-25 49 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正確編譯的代碼,但在從上javac的命令行編譯

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); 

存在用於unregistering/enabling/disabling產生相同的錯誤事件類似的方法所產生的誤差。 從上面的代碼我試圖除去registerManagedHandler類型約束(<T extends Event, P extends EventHandler<T>>)但然後註冊(...)方法調用產生的錯誤

我的改性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(...)方法中刪除類型檢查。

如果需要了解更多代碼細節,請告知我。

請告訴我處理此類問題或解決方法的正確方法。我對泛型非常陌生,但在實現此功能之前,我閱讀了基本指南。

另外我找不到任何方法強迫eclipse使用安裝在我的Ubuntu系統上的sun-javac6而不是它自己的編譯器。雖然我知道如何更改eclipse中的JRE(項目 - >屬性 - > Java構建路徑 - >庫)

在此先感謝。

更新:謝謝你們的迴應。告訴我是否可以提供更多信息。我的Eclipse版本是Indigo(3.7)

這是sscce。如果你在eclipse中運行該程序,它可以正常工作(編譯和執行)。但是當你用命令行運行它時:即javac GenericTester.java,則會出現以下錯誤。我已經用sscce.org的編譯器工具證實了這一點。從命令行

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$ 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 

約我已經安裝了Java的一些詳細信息。

[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

爲了更好地幫助越早,張貼[SSCCE](http://sscce.org/)。鑑於第一'?'是低於你的帖子提示我問..是你的問題「爲什麼SDK和Eclipse編譯器之間的行爲差​​異?」。如果是這樣,那麼我建議你添加,作爲編輯,讓你的問題..一個問題。 – 2012-03-25 11:38:43

+0

@Nitraj您確定在命令行中使用的JDK與Eclipse用於編譯的相同嗎?你可以在你的問題中添加你正在使用的命令行嗎? – 2012-03-25 12:24:23

+0

爲了重現您的編譯錯誤,瀏覽5個代碼片段中的不完整源代碼傳播非常困難。如果您希望我們幫助您,請發佈SSCCE。提示:如果你使用默認可見性(即非公開)聲明你的類型,它們都可以進入相同的源文件,這使得將代碼導入eclipse變得更容易。 – meriton 2012-03-25 13:25:50

回答

0

我不認爲我們有足夠的細節來回答你的第一個問題。 但是,對於你的第二個問題,你可以使用喜好配置的Java運行時環境 - >爪哇 - >安裝的JRE,你可以配置使用首你的Java編譯器合規水平 - >爪哇 - >編譯器

enter image description here

0

爲什麼JDK 1.6拒絕編譯SSCCE的解釋:Compilers behave differently with a null parameter of a generic method

在Java 7,對於沒有出現在參數類型或返回值類型變量推理算法extended到考慮類型參數的邊界。事實上,您的SSCCE通過JDK 1.7.0_02中的javac成功編譯。

這就是說,我認爲你的registerEvent濫用泛型:方法的類型參數是由調用者指定的(通常由類型推斷算法指定,但它們只能被明確指定),但是如果實際調用者輸入的參數與EventRegistry的參數相匹配,而編譯器不檢查它們。考慮:

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

編譯並運行良好,但實際上會觸發事件時可能會導致ClassCastException。這就是爲什麼我不會推薦將類作爲字符串傳遞的原因。

如果你真的需要他們的字符串,以獲得花哨的類加載器,你至少應該檢查類實現正確的類型:

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); 
} 

隨着該實現,試圖訂閱StringEventHandler將導致ClassCastException

該代碼還不夠完善,如編譯器警告提醒我們這樣一個事實,我不檢查事件處理程序有正確的類型參數,所以調用者仍然可以這樣做:

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

即使盡管MyEventHandler無法處理所有Event s。但是,由於類型擦除,驗證EventHandler的事件類型通常是不可能的。