Я пытаюсь создать API, где клиент может зарегистрировать слушателя, который получает события. Метод слушателя, который вызывается для события, принимает аргумент. API должен позволить клиенту решить, должен ли этот аргумент быть экземпляром конкретного класса или экземпляром интерфейса (чтобы избежать ненужных приведений в реализациях прослушивателя клиента). Для этого я поиграл с дженериками. Работает нормально, кроме одного случая!
Клиент реализует интерфейс (см. Пример в MyListener1Impl.java и MyListener2Impl.java) и может с помощью шаблонов определить тип аргумента события.
Статический метод фабрики используется для получения экземпляра ClassABuilder.java. Метод build () ClassABuilder возвращает экземпляр 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
}
}