Java - расширение класса как возвращаемого типа в интерфейсе/абстрактном методе

Я пытался найти способ создать интерфейс/абстрактный метод с объявлением/расширением класса в качестве возвращаемого типа. (например, classA расширяет интерфейс A, и метод должен возвращать объект ClassA).

Теперь я нашел сообщение о том, что компилятор не будет жаловаться на что-то подобное, но JVM не может справиться с такими вещами, а это означает, что эта механика просто не существует в java.

Поэтому я пришел к следующей идее, из которой я понятия не имею, достаточно ли это технически безопасно, чтобы сделать. (например, вызовет ли это петлю)

public interface ISomeInterface<T extends ISomeInterface<T>> {
    public T get();
}

это означает, что вы можете использовать его таким образом. Хотя это не заставляет внешнего пользователя использовать расширяющий класс, но, по крайней мере, дает возможность сделать это, если это необходимо:

public class ExtendingClass implements ISomeInterface<ExtendingClass>{
    @Override
    public ExtendingClass get(){}
}

Теперь это не дает компилятора или ошибки времени выполнения, но меня беспокоит, не создаст ли это каких-либо проблем при интенсивном использовании.

Я был бы признателен, если бы кто-то мог подтвердить, что это вызовет или не вызовет проблем. (любые другие отзывы также приветствуются).


person n247s    schedule 02.04.2016    source источник
comment
Я думаю, что это работает нормально. Это тот же шаблон, который Java использует для типов enum, которые объявляются как общедоступный класс Enum‹E расширяет Enum‹E››   -  person markspace    schedule 02.04.2016
comment
Как это не дает вам ошибку компиляции? Класс реализации не является абстрактным, поэтому для этого вам потребуется тело метода.   -  person Makoto    schedule 02.04.2016
comment
@Makoto это действительно выдаст ошибку: D, это был просто пример. поменял сейчас.   -  person n247s    schedule 02.04.2016
comment
@markspace хорошо, я этого не знал. Мне этого достаточно о безопасности :D, большое спасибо!   -  person n247s    schedule 02.04.2016


Ответы (2)


В этом нет ничего плохого. На самом деле это довольно распространенная практика.

person Mureinik    schedule 02.04.2016
comment
Хорошо, спасибо. Я очень надеюсь, что однажды будет лучшее решение для этого. - person n247s; 02.04.2016

Это очень распространенная практика. Примеры включают:

Enum<E extends Enum<E>>

BaseStream<T, S extends BaseStream<T, S>>

Тем не менее, убедитесь, что вы знаете об ограничениях. Главный из них заключается в том, что он плохо работает с наследованием.

Например, если у вас есть интерфейс

interface Animal<A extends Animal<A>>

вы можете решить написать конкретную реализацию, подобную этой

class Duck implements Animal<Duck>

Это прекрасно работает, но если вы позже решите, что хотите расширить Duck, вы не сможете написать это:

class MallardDuck extends Duck implements Animal<MallardDuck>

Причина, по которой вы не можете этого сделать, заключается в том, что вы не можете реализовать один и тот же общий интерфейс с двумя параметрами разных типов — поскольку Duck уже реализует Animal<Duck>, MallardDuck не может реализовать Animal<MallardDuck>.

Итак, убедитесь, что если вы используете этот шаблон, вы очень тщательно продумываете, как вы собираетесь реализовать интерфейс. Он работает с Enum, потому что язык не позволяет вам расширять их, но если использовать его слишком часто, этот шаблон может создать полный беспорядок.

person Paul Boddington    schedule 02.04.2016
comment
Это кажется логичным. хотя разве это не относится и к обычным интерфейсам? он в основном скрывает общие типы. Хотя я понимаю, что вы имеете в виду, поскольку метод имеет тип возврата «Утка» (в данном случае), подкласс больше не может изменить этот тип возврата. Хотя это ничем не отличается от обычного интерфейса. В любом случае спасибо за указание. - person n247s; 02.04.2016