[英]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?
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")
很好。
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。 還不夠嗎?
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
已經包含有關類的信息,可以由它處理,因此它是信息重復。
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.