There is a certain interface:

public interface ViewableParent<C extends AfdxObject> extends Viewable{ interface ListChangeCallback<C>{ void doWhenChange(C object); } ListChangeCallback<C> getAddedSubListCallback(); ListChangeCallback<C> getRemovedSubListCallback(); default ListChangeListener<C> getChangeListener(){ return c -> { while (c.next()){ if (c.wasAdded()) { //Проходимся по добавленным элементам c.getAddedSubList().forEach(e -> { //Вешаем на проперти стиля слушатель, который при изменении стиля потомка меняет стиль у родителя e.styleProperty().addListener((observable, oldValue, newValue) -> refreshStyle(c.getList(), ViewableParent.this,false)); //Выполяняем код add коллбэка if (getAddedSubListCallback()!=null) getAddedSubListCallback().doWhenChange(e); }); //Пересчитываем стиль для родителя исходя из стилей добавляемых потомков refreshStyle(c.getAddedSubList(), ViewableParent.this,true); } else if (c.wasRemoved() || c.wasUpdated()) { //Иначе, если что-то было удалено или обновлено (здесь не уверен в корректности события update) //Так же пересчитываем стиль для родителя refreshStyle(c.getList(), ViewableParent.this, false); //Выполняем код remove коллбэка if (getRemovedSubListCallback()!=null) c.getRemoved().forEach(e -> getRemovedSubListCallback().doWhenChange(e)); } } }; } } 

The type C parameter denotes the descendant type for the class implementing this interface. 4 out of 5 classes have only one type of descendant, however there is one class in which there are descendants 2. If the class declaration declares 2 times the same interface with different types in the generic, the IDE itself gives an error. Tell me how to circumvent this limitation in terms of architecture?

  • it's impossible. from the point of view of java, the interface <A> and Interface <B> bytecode are the same. And no one will allow you to implement the same interface twice - Artem Konovalov
  • specifically, the problem here is not even in type erasure, but in the fact that you will have two methods with the same signature, but different return types, but you cannot. How do you want to use a class that implements two interfaces? - zRrr
  • @zRrr, I understand why this can not be done. The question is in the way of circumventing this problem from the point of view of the architectural component, for example, in the form of some kind of pattern, etc. The interface has tests, with the other classes it works fine, so I don’t want to duplicate code in the class by rewriting the default method - I. Perevoz
  • you can make a method like ViewableParent<B> asVPB() which will return a view: an object of an anonymous class that implements the methods of the ViewableParent<B> interface and calls the methods of the main class. - zRrr
  • @zRrr thought at first to do the same. However, at the moment he stopped at getting rid of the interface in favor of the method in the utilitarian class. - I. Perevoz

2 answers 2

You will not be able to implement an interface with different parameterized types twice:

 interface MyInterface<T>{ T method(); } class MyClass implements MyInterface<A>, MyInterface<B>{ ... } 

Because type erasing occurs, and only interfaces with the Object type are left in bytecode. Those. for java MyInterface<A> and MyInterface<B> same thing.

Even if there were no erasure, logical errors would have occurred. As noted earlier by @zRrr, a situation may arise that a class implements two identical methods, with a different return type.

 public A method(){ ... } public B method(){ ... } 

When called, it is not clear what to call, and in java such code is not correct.

If you really want to, you can do it, but again, it depends on the signatures of the interface methods and will not work in all cases. For the Comparable interface Comparable it looks like this:

 class A implements Comparable<A> { @Override public int compareTo(A o) { return 0; } } class B implements Comparable<B> { @Override public int compareTo(B o) { return 0; } } //E extends A or B class Gibrid<E> implements Comparable<E> { final A a = new A(); final B b = new B(); @Override public int compareTo(E o) { if (o instanceof A) return a.compareTo((A) o); else if (o instanceof B) return b.compareTo((B) o); throw new IllegalArgumentException("object type is not correct." +"It must be A or B"); } } 

But here we move away from type checking at compile time during program execution.

  • Thanks for the answer. However, as I wrote in the commentary on the question, I understand why this cannot be done. I am interested in a workaround in terms of architecture. Any wrapper or something like that. - I. Perevoz

As a result, I had to abandon the use of a generic in the interface description and slightly extend the default method. I do not know yet how justified and correct this is, but everything works. The only point: it is not clear that in this situation it would be more correct. To render the callback interface and default method as static in the utility class or leave it like that? In this case, the behavior of the method is not planned to override.

 public interface ViewableParent extends Viewable{ interface ListChangeCallback<C>{ void doWhenChange(C object); } default <C extends Viewable> ListChangeListener<C> getViewChangeListener(ListChangeCallback<C> addCallback, ListChangeCallback<C> removeCallback){ return c -> { while (c.next()){ if (c.wasAdded()) { //Проходимся по добавленным элементам c.getAddedSubList().forEach(e -> { //Вешаем на проперти стиля слушатель, который при изменении стиля потомка меняет стиль у родителя e.styleProperty().addListener((observable, oldValue, newValue) -> refreshStyle(c.getList(),false)); //Выполяняем код add коллбэка if (addCallback!=null) addCallback.doWhenChange(e); }); //Пересчитываем стиль для родителя исходя из стилей добавляемых потомков refreshStyle(c.getAddedSubList(),true); } else if (c.wasRemoved() || c.wasUpdated()) { //Иначе, если что-то было удалено или обновлено (здесь не уверен в корректности события update) //Так же пересчитываем стиль для родителя refreshStyle(c.getList(),false); //Выполняем код remove коллбэка if (removeCallback!=null) c.getRemoved().forEach(removeCallback::doWhenChange); } } }; } }