![](/img/trans.png)
[英]Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?
[英]How can an interface include a method that references the concrete implementation type of the interface in its signature or return type?
假設我正在設計類似以下界面的內容:
public interface MyInterface{
public MyInterface method1();
public void method2(MyInterface mi);
}
但是,需要注意的是, method1
的返回類型和method2
的參數與具體實現匹配,而不僅僅是MyInterface
。 也就是說,如果我有MyInterfaceImpl
實現MyInterface
,它需要具備以下條件:
public class MyInterfaceImpl implements MyInterface{
@Override
public MyInterfaceImpl method1(){...}
@Override
public void method2(MyInterfaceImpl mi){...}
}
如上所述, method1
不會導致任何編譯錯誤,但是不能保證在所有實現中返回類型都匹配。 當然method2
甚至不會編譯,因為簽名與接口不匹配。
一種候選解決方案是在泛型中使用自引用或遞歸范圍:
public interface MyInterface<T extends MyInterface<T>>{
public T method1();
public void method2(T mi);
}
public class MyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
@Override
public MyInterfaceImpl method1();
@Override
public void method2(MyInterfaceImpl mi);
}
這將使我得到我想要的東西,但有一個例外:其他實現可能傳遞了錯誤的泛型類型(沒有力T
匹配具體類型)。 因此,可能其他人可以實現以下目標:
public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
@Override
public MyInterfaceImpl method1();
@Override
public void method2(MyInterfaceImpl mi);
}
即使NotMyInterfaceImpl
應該實現MyInterface<NotMyInterfaceImpl>
也可以很好地編譯。*這使我認為我還需要其他東西。
*請注意,我不認為我要違反LSP; 我可以將返回類型/參數設置為NotMyInterfaceImpl
子類。
所以我不知道這樣做的干凈方法。 這使我相信我可能會過多地關注界面中的實現細節,但對我而言似乎並非如此。 有什么方法可以做我描述的事情,還是我在某種不屬於該接口的接口中聞到這種氣味?
這是Comparable
接口所面臨的確切情況(其compareTo
方法要采用與調用它的對象相同類型的參數)。 那怎么辦呢? 它被簡單地定義為Comparable<T>
。 這個想法是,一個實現類“應該”將Comparable
與自身實現為參數(允許它與自身“比較”)。 但這不是強制性的(因為沒有辦法這樣做)。
是的,正如您所指出的,這將允許任何類使用任何其他類的參數來實現Comparable
: class Foo implements Comparable<Bar>
,其中Foo
和Bar
彼此無關。 但是,這並不是真正的問題。
所有需要Comparable
對象的方法和類(排序,最大值等)都具有以下通用類型約束<T extends Comparable<? super T>>
<T extends Comparable<? super T>>
。 這樣可以確保T類型的對象與其自身具有可比性。 這樣,它是完全類型安全的。 因此,實施不是在Comparable接口的聲明中進行的,而是在使用它的地方進行的。
(我注意到您使用<T extends MyInterface<T>>
而Comparable
僅使用<T>
。盡管<T extends MyInterface<T>>
會排除類型參數未實現MyInterface
,但不會排除其中類型參數確實實現了MyInterface
,但與類有所不同,因此排除某些情況的意義何在呢?如果您采用Comparable
的方式將其限制在使用它們的地方,那么無論如何它都是類型安全的,所以沒有意義添加更多限制。)
我相信這是不可能的。 據我所知,根本沒有辦法在泛型框架中引用對象的實現類,就我所知,也沒有任何方法可以用純泛型構造籠子,這種籠子能夠約束實現類以匹配類型參數。
我可以建議的最有用的方法是使用自引用參數,然后始終從工廠方法中獲取實現實例,如下所示:
public <T extends MyInterface<T>> T newInstance();
駱駝穿過針眼要比NotMyInterfaceImpl
實例通過該返回類型NotMyInterfaceImpl
。 因此,盡管麻煩制造者可能編寫的類與您的總體規划不符,但他們無法從工廠退還它們。 除非NotMyInterfaceImpl
擴展了MyInterfaceImpl
; 但是從某種意義上講,它也將是MyInterfaceImpl
,所以也許是猶太潔食?
編輯:該想法的一個稍微有用的版本是始終在適當限制的持有人周圍傳遞接口的實現實例,例如:
class Holder<T extends MyInterface<T>> {
public final T value;
}
如果有人給您Holder<Q>
,那么您知道Q
必須是綁定到其自身的MyInterface
的版本,這就是您所追求的。
您嘗試執行的操作是不合法的,因為您嘗試縮小已實現類型的參數,而這“沒有道理” 。 您正在嘗試使用“ covariant”參數 ,並且僅允許使用協變返回類型(甚至是邏輯,並且僅Java 5支持 )。
我的意思是,如果可以使用協變參數類型,則可以執行以下操作:
MyInterface instance = new MyInterfaceImpl();
然后,通過接口支持但MyInterfaceImpl類不支持的另一個實現在“實例”上調用該方法:
instance.method2(new MyInterfaceImpl_2());
Java無法將MyInterfaceImpl_2
轉換為MyInterfaceImpl
,因此它阻止您在編譯時這樣做。
您可以做的是使用“ contravariant”參數擴展參數,這很合理。 有關此的更多詳細信息,請檢查以下分析器:
我能想到的唯一解決方法是在運行時解決問題,這是說:
public class MyInterfaceImpl implements MyInterface{
@Override
public void method2(MyInterface mi){
realMethod((MyInterfaceImpl) mi);
}
public void realMethod(MyInterfaceImpl) {...}
}
但是,您當然可以得到ClassCast異常。
返回接口的目的是使該方法不關心返回對象的實際實現。 在您的情況下,您實際上希望將類型強制為該接口的特定子實現。
若要應用您上面描述的約束,恕我直言,設計可能應該是基類而不是接口。 這使您可以控制實現,例如頂層流程,並將低級策略留給子類來實現:
class MyBaseImpl {
public final void fixedFlow() {
MyBaseImpl obj = method1();
obj.method2(this);
}
protected abstract MyBaseImpl method1();
....
}
必須有其他使它變得有趣的方法。 也許您有充分的理由要這樣做...
希望這可以幫助!
這是你想要的?
public interface MyInterface {
static abstract class MyInterfaceImpl implements MyInterface {
@Override
public abstract MyInterfaceImpl method1();
@Override
public abstract void method2(MyInterfaceImpl mi);
}
MyInterfaceImpl method1();
void method2(MyInterfaceImpl mi);
}
您甚至可以實現方法1或2,而不用抽象它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.