簡體   English   中英

讓一個類在java中實現一個未指定的泛型接口

[英]Have a class implement an unspecified generic interface in java

我有以下“通用”問題

這是我的通用消息界面。

public interface Message<P,R> {  
    void setParams(P Params); // and the corresponding getter  
    void setResults(R results);  
}  

為簡單起見,我想通過預定義參數和結果類型來指定消息的數量(接口)。 因此,如果您使用消息X,您就知道params和結果類型是什么。

public interface MyMessage extends Message<String,String> {}  

這工作正常,現在我想有一個可以實現任何消息的公共基類。

public class BaseMessage<P,R> implements Message<P,R> {
    P param;
    R results;
    // base implementation
}

現在的問題是我不能有一個實現MyMessage的BaseMessage。

多次嘗試就好

public class BaseMessage<T extends BaseMessage<P,R>> implements Message<P,R> 

要么

public class BaseMessage<? extends BaseMessage<P,R>> implements Message<P,R> 

將無法正常工作,因為編譯器抱怨P和R沒有綁定。 將它們作為附加參數引入再次工作,但是在那一刻,結果類將不能轉換為BaseMessage或所需的MyMessage。

public class BaseMessage<P,R,T extends BaseMessage<P,R>> implements Message<P,R> 

我想有一個通用的工廠方法,它將被賦予消息類,參數和結果對象,並將返回實現MyMessage接口的BaseMessage實例。 喜歡在下面

public static <P, R, T extends Message<P,R>> T factory(Class<T> clazz,P p,R r) {
    T a = (T) new BaseMessage<P,R>();
    // create a BaseMessage which which Implements T
    a.setParams(p);
    a.setResults(r);
    return a;
}

任何人都遇到類似的問題,或者是Java中不可能出現的問題?

謝謝!

我擔心這樣的通用工廠是不可能的,因為你無法實例化類似的泛型類型

T a = new BaseMessage<T>();

您必須告訴編譯器確切的泛型類型參數。

可以做的是創建每個具體消息類型的實例,並將它們存儲在地圖中,並將相應的類標記作為關鍵字。 然后工廠方法可以查找正確的消息並直接返回它,或者(如果需要單獨的實例)使用消息對象作為原型來創建要返回的實例。

在我們當前的項目中,我們有一些類似的設計,不同之處在於具體的子類是每個現有的類,具有不同的名稱和(不幸的是 - 但不是完全 - 重復的)實現。 所以我們可以使用標准類加載和Spring來實例化它們。

您尚未指定工廠如何決定使用哪個實現類,或者實現類是否需要任何自定義初始化邏輯或參數。 假設只使用默認構造函數實例化已注冊的實現類就足夠了,您可以這樣做:

interface Message<P, R> {
    void setParams(P Params); // and the corresponding getter

    void setResults(R results);
}

interface StringMessage extends Message<String, String> {
}

abstract class MessageImpl<P, R> implements Message<P, R> {
    P param;
    R results;
}

abstract class StringMessageImpl extends MessageImpl<String, String> implements
        StringMessage {

}
class ImplementationMap {
    private Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();

    public <T> void register(Class<T> interfaceClass, Class<? extends T> implementationClass) {
        map.put(interfaceClass, implementationClass);
    }

    public <T> Class<? extends T> get(Class<T> interfaceClass) {
        return map.get(interfaceClass).asSubclass(interfaceClass);
    }
}

public class Test {
    static final ImplementationMap messageImplementors = new ImplementationMap() {{
        register(StringMessage.class, StringMessageImpl.class);
    }};

    static <P, R, M extends Message<P, R>> M create(Class<M> clazz, P p, R r)
            throws Exception {
        M m = messageImplementors.get(clazz).newInstance();
        m.setParams(p);
        m.setResults(r);
        return m;
    }

    public static void main(String[] args) throws Exception {
        StringMessage m = create(StringMessageImpl.class, "p", "r");
    }
}

PS:你確定你沒有過度工程嗎? 您真的需要DTO的並行類型層次結構嗎?

給定接口interface Message<P,R>interface MyMessage extends Message<String, String> ,類class BaseMessage<P,R> implements Message<P,R> ,這些是我看到的選項:

  1. 不要使用MyMessage並使用Message<String, String>替換所有實例。 你的工廠將是

     public <P,R> Message<P, R> newMessage() { return new BaseMessage<P,R>(); } 
  2. 有一節課

     class MyBaseMessage extends BaseMessage<String, String> implemens MyMessage 

    工廠將是

     public <M extends Message> M newMessage(Class<M> m) { if (m.isAssignableFrom(MyBaseMessage.class)) { return (M) new MyBaseMessage(); } if (m.isAssignableFrom(BaseMessage.class)) { return (M) new BaseMessage(); } return null; } 
  3. 不要使用接口。

  4. 不要使用工廠。

  5. (如果其他一切都破了)讓你的工廠成為

     public <M extends Message> M newMessage(Class<M> m) { try { return getImplClass(m).newInstance(); } catch (Exception ex) { /* do proper error handling */ } } 

    getImplClass() :使用javassist在運行時創建實現類,實現接口M並擴展BaseMessage。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM