[英]Factory method returning Builder does not compile with generics. What is wrong?
我正在嘗試構建一個API,客戶端可以在其中注冊接收事件的偵聽器。 在事件上調用的偵聽器方法帶有一個參數。 API應該讓客戶端決定該參數是具體類的實例還是接口的實例(以避免在客戶端偵聽器實現中進行不必要的強制轉換)。 為此,我使用了泛型。 正常,除了一種情況!
客戶端實現一個接口(請參見MyListener1Impl.java和MyListener2Impl.java中的示例),並且可以使用泛型來確定事件的參數類型。
靜態工廠方法用於檢索ClassABuilder.java的實例。 ClassABuilder的build()方法返回ClassA.java的實例。
由於某種原因,當將Factory方法與Builder模式一起使用(以伸縮形式調用方法)並且將具體的偵聽器實現用作泛型類型參數時,它不會編譯(請參閱設置變量“ c4”的位置) 。 誰能告訴我為什么? 怎么了?
請參閱下面的完整示例代碼。 將以下類復制/粘貼到Eclipse(或任何其他IDE)中,您將看到它無法編譯的地方。
Main.java類
public class Main{
public static void main(String[] args){
// Works ok when generic type argument is set to interface "AnyFile".
// MyListener2Impl has also declared "AnyFile"
ClassABuilder<AnyFile> builder0 = Factory.newClassABuilder();
builder0.set(new MyListener2Impl());
ClassA<AnyFile> c0 = builder0.build();
// Also Works ok when methods are called in telescope form
// (not sure "telescope" is the correct term?)
ClassA<AnyFile> c1 = Factory.newClassABuilder()
.set(new MyListener2Impl())
.build();
// Works ok when generic type argument is set to concrete "MyFileImpl".
// MyListener1Impl has also declared "MyFileImple"
ClassABuilder<MyFileImpl> builder2 = Factory.newClassABuilder();
builder2.set(new MyListener1Impl());
ClassA<MyFileImpl> c2 = builder2.build();
// also works ok with telescop form, but Factory class is NOT used.
ClassA<MyFileImpl> c3 = new ClassABuilder<MyFileImpl>().set(new MyListener1Impl()).build();
// But with static factory method AND telescope style, it does not compile! Why? What is wrong?
ClassA<MyFileImpl> c4 = Factory.newClassABuilder()
.set(new MyListener1Impl())
.build();
}
}
類AnyFile.java
import java.util.List;
public interface AnyFile {
List<AnyFile> listFiles();
}
ClassA.java類
public class ClassA <T extends AnyFile>{
}
ClassABuilder.java類
public class ClassABuilder <T extends AnyFile>{
public ClassABuilder<T> set(Listener<T> a){
return this;
}
public ClassA<T> build(){
return new ClassA<T>();
}
}
類Factory.java
public class Factory {
public static <T extends AnyFile> ClassABuilder<T> newClassABuilder(){
return new ClassABuilder<T>();
}
}
Listener.java類
public interface Listener <T extends AnyFile>{
void event(T file);
}
類MyFileImpl.java
import java.util.List;
public class MyFileImpl implements AnyFile{
@Override
public List<AnyFile> listFiles() {
// do something...
return null;
}
}
類MyListener1Impl.java
public class MyListener1Impl implements Listener<MyFileImpl>{
@Override
public void event(MyFileImpl file) {
// do something
}
}
類MyListener1Impl.java
public class MyListener2Impl implements Listener<AnyFile>{
@Override
public void event(AnyFile file) {
// do something
}
}
簡短的答案是Java的類型推斷功能不足以從左到右進行推斷。 也就是說,在調用.set()
方法之前,必須知道Factory.newClassABuilder()
的類型<T>
(將用於參數化ClassA
),並且Java無法推斷出Factory.newClassABuilder()
的返回類型。從在該返回類型上調用的方法的參數中得出。
這種推斷需要整個程序的分析,很少有語言會這樣做,而Java絕對不支持。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.