簡體   English   中英

返回Builder的工廠方法不使用泛型進行編譯。 怎么了?

[英]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.

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