簡體   English   中英

類繼承:泛型擴展了泛型

[英]Class inheritance: generic extends generic

假設我的課程很簡單

public class MyObject {
}

和處理程序接口,用於處理MyObject的子類

public interface MyObjectHandler<V extends MyObject>{
     List<V> handle(List<V> objects);
}

假設我有BigObjects和SmallObjects(它們都擴展了MyObject),並且我想為它們提供單獨的處理程序。 因此,我使用特定的泛型創建了MyObjectHandler的兩個接口。

class BigObject extends MyObject {}
class SmallObject extends MyObject {}

// Handlers interfaces
interface BigObjectHandler extends MyObjectHandler<BigObject>{}
interface SmallObjectHandler extends MyObjectHandler<SmallObject>{}

// Concrete handlers
class BigHandler1 implements BigObjectHandler {....}
class BigHandler2 implements BigObjectHandler {....}

class SmallHandler1 implements SmallObjectHandler {....}
class SmallHandler2 implements SmallObjectHandler {....}

現在讓我們想象一下,我們已經創建了AbstractHandlerChain<...>抽象類。 因此,我們可以創建BigHandlerChain類並注入BigHandlers(與SmallHandlerChain相同)。

class BigHandlerChain extends AbstractHandlerChain<BigObjectHandler> {
    // Inject only childs of BigObjectHandler. E.g. via spring @Autowired
    public BigHandlerChain(List<BigObjectHandler> handlers) {
        this.handlers = handlers;
    }
} 

問題:是否可以為這種情況創建完美的AbstractHandlerChain?

可能的解決方案1

public abstract class HandlerChain<T extends MyObjectHandler> {

    private List<T> handlers;

    public HandlerChain(List<T> handlers) {
        this.handlers = handlers;
    }

    public <V extends MyObject> List<V> doChain(List<V> objects) {
        for (T handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }
}

這是handler.handle(objects) ,但是在handler.handle(objects)我得到了Unchecked call to 'handle(List<V>)' as a member of raw type 'MyObjectHandler' ,因此我應該添加@SuppressWarnings("unchecked")很好。

可能的解決方案2

public abstract class HandlerChain<T extends MyObjectHandler<? extends MyObject>> {

    ...

    public <V extends MyObject> List<V> doChain(List<V> objects) {
        for (T handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }
}

不起作用 handler.handle(objects)我無法將handle (java.util.List<capture<? extends MyObject>>) cannot be applied to (java.util.List<V>) 為什么在這種情況下不能將對象傳遞給處理程序? 通配符擴展MyObject,而V擴展MyObject。 還不夠嗎?

可能的解決方案3

public abstract class HandlerChain<T extends MyObjectHandler<V>, V extends MyObject> {

    ...

    public List<V> doChain(List<V> objects) {
        for (T handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }
}

這是可行的,但在這種情況下,我應該在class BigHandlerChain extends AbstractHandlerChain<BigObjectHandler, BigObject>情況下定義BigHandlerChain。 但是BigObjectHandler已經包含有關類的信息,可以由它處理,因此它是信息重復。

可能的解決方案4

public abstract class HandlerChain<T extends MyObjectHandler<V extends MyObject>> {

    ...

    public List<V> doChain(List<V> objects) {
        for (T handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }
}

這是我希望從Java獲得的解決方案,但是它不起作用! 我不能像這樣聲明類...class HandlerChain<T extends MyObjectHandler<V extends MyObject> 為什么我可以在MyObjectHandler之后使用通配符,但不能使用這種構造?

解決方案1

這是可行的,但在handler.handle(objects)中,作為原始類型'MyObjectHandler'的成員,我得到了'handle(List)'的未經檢查的調用,因此我應該添加不是很好的@SuppressWarnings(“ unchecked”)。

確實,因為MyObjectHandler是泛型類型,但是您不必在HandlerChain的type參數中HandlerChain指定類型。

解決方案2

不起作用 在handler.handle(objects)中,我無法將句柄(java.util.List>)應用於(java.util.List)。 為什么在這種情況下不能將對象傳遞給處理程序? 通配符擴展MyObject,而V擴展MyObject。 這還不夠嗎?

不。 ? extends MyObject ? extends MyObject基本上是說它用於某些未指定的類型,擴展了MyObject ,但您並沒有說明。 您可以創建一個public class BigHandlerChain<BigObjectHandler>但向doChain提供SmallObject實例列表。

解決方案3

這是可行的,但是在這種情況下,我應該在BigHandlerChain類擴展AbstractHandlerChain的同時定義BigHandlerChain。 但是BigObjectHandler已經包含有關類的信息,可以由它處理,因此它是信息重復。

確實,這里有一些重復的信息,但是當合成這樣的泛型類型時,很可能會發生這種情況。 由於您的doChain方法對某種類型進行操作,因此必須指定該類型可以做什么。 看到它說您將要處理BigObject列表,並且您提供的處理程序必須能夠處理BigObjects。

解決方案4

這是我希望從Java獲得的解決方案,但是它不起作用! 我無法聲明此類... class HandlerChain。 為什么我可以在MyObjectHandler之后使用通配符,但不能使用這種構造?

問題在於V表示某種特定類型,而不是通配符,因此您需要指定V是什么。

換句話說,盡管有一些重復的信息,您的解決方案3是正確的方法。 不幸的是,您將在Java中看到更多信息。 當字段上的特定修飾符關鍵字可以實現相同的功能時(例如在Ruby中),獲取器/設置器無疑是不必要的樣板。

但是請注意,如果您指定public abstract class HandlerChain<T extends MyObjectHandler<V>, V extends MyObject> ,則指定鏈僅適用於一種特定類型的MyObjectHandler 由於我認為您可能需要一系列不同的處理程序,這些處理程序都能夠處理相同的對象類型,因此最好只指定該對象類型:

public abstract class HandlerChain<V extends MyObject> {

    private List<MyObjectHandler<V>> handlers;

    public HandlerChain(List<MyObjectHandler<V>> handlers) {
        this.handlers = handlers;
    }

    public List<V> doChain(List<V> objects) {
        for (MyObjectHandler<V> handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }

}

您不需要處理程序是通用的,只需要對象:

public abstract class HandlerChain<V extends MyObject> {

    private List<MyObjectHandler<V>> handlers;

    public HandlerChain(List<MyObjectHandler<V>> handlers) {
        this.handlers = handlers;
    }

    public List<V> doChain(List<V> objects) {
        for (MyObjectHandler<V> handler : handlers) {
            objects = handler.handle(objects);
        }
        return objects;
    }

}

這允許:

    new HandlerChain<BigObject>(Arrays.asList(new BigHandler1(), new BigHandler2())) {
        // ...
    };

編輯:如果您比較G_H的解決方案和我的,唯一的區別是G_H使用List<? extends MyObjectHandler<V>> List<? extends MyObjectHandler<V>> 這使您可以傳遞一個列表,該列表具有聲明為比MyObjectHandler<V>更具體的元素類型。 我認為您不太可能需要此功能,但是您也可以采取這種額外的靈活性,以防萬一。

修復解決方案4很簡單,因為:Java編譯器期望通配符一起聲明,然后再使用:

public abstract class HandlerChain<V extends MyObject, T extends MyObjectHandler<V>>
{
    private List<T> handlers;

    public List<V> doChain(List<V> objects)
    {
        for (T handler : handlers)
        {
            objects=handler.handle(objects);
        }
        return objects;
    }
}

暫無
暫無

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

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