Головоломка с дженериками

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

У меня есть:

interface Root { }
interface Middle extends Root { }
class Type implements Root { }

И многие классы "Подтип":

class Subtype1 extends Type implements Middle { }
class Subtype2 extends Type implements Middle { }
...

Я хочу объявить класс с двумя параметрами типа T и S, где T связан с Type, а S связан с T и Middle.

Я не вижу способа с помощью дженериков гарантировать, что S расширяет T И реализует Middle. Я хочу что-то вроде:

class Handler<T extends Root, S extends T, S extends Middle>;

or

class Handler<T extends Root, S extends <T extends Middle>>;

Но, конечно, ни то, ни другое не является законным. Может быть, я упускаю какую-то магию?


person Nick Palmer    schedule 27.03.2013    source источник
comment
Ты не сможешь это сделать. У вас может быть несколько границ, но они должны быть класса 0-1 плюс несколько интерфейсов. У вас не может быть универсального типа в ситуации множественной привязки. Я подозреваю, что это ограничение было сохранено, потому что разрешение ввода с несколькими границами создало бы большую сложность для проверки синтаксиса, что является редким пограничным случаем.   -  person BevynQ    schedule 28.03.2013
comment
связанные: stackoverflow.com/a/13261667/697449   -  person Paul Bellora    schedule 28.03.2013
comment
Спасибо. Я тоже это читал, но подумал, что, возможно, я что-то упустил в спецификации. Отливки это!   -  person Nick Palmer    schedule 28.03.2013
comment
Можете ли вы объяснить, почему объявления Handler<T extends Root, S extends Subtype> недостаточно? Единственная разница в том, что T может быть более конкретным типом, чем S, вот и все.   -  person Paul Bellora    schedule 28.03.2013
comment
Handler<T extends Root, S extends Subtype> означает, что обработчик привязан к одному подтипу. У меня есть несколько, что означает, что обработчик больше не является общим для подтипов. На самом деле мой код имеет полдюжины подтипов, что означает равное количество обработчиков, привязанных к конкретному подтипу.   -  person Nick Palmer    schedule 28.03.2013
comment
Я внес некоторые изменения, чтобы попытаться прояснить вашу проблему. Не могли бы вы просмотреть мои изменения и сообщить мне, если что-то не так?   -  person Paul Bellora    schedule 28.03.2013


Ответы (2)


Попробуйте ввести абстрактный класс, расширяющий SubType и реализующий Middle, чтобы его тип можно было использовать в Handler.

abstract class MiddleSubtype extends Subtype implements Middle { }

Потом,

class Handler<T extends Root, S extends MiddleSubtype> {  //...

EDIT: после обновления вопроса та же идея будет выглядеть так:

abstract class MiddleType extends Type implements Middle { }

class Subtype1 extends MiddleType { }
class Subtype2 extends MiddleType { }
...

class Handler<T extends Root, S extends MiddleType> {  //...
person rgettman    schedule 27.03.2013
comment
Обратите внимание, что это отличается от T extends Root, S extends T ..., поскольку S больше не связано с T. - person Paul Bellora; 28.03.2013
comment
Да, и это связывает Handler с одним подтипом. На самом деле у меня есть куча подтипов, которые также означают кучу обработчиков, чего я и пытался избежать. - person Nick Palmer; 28.03.2013
comment
@NickPalmer Посмотрите мое редактирование этого ответа - я думаю, что это близко к тому, что предлагал rgettman. - person Paul Bellora; 28.03.2013
comment
Это действительно работает для поставленного пересмотренного вопроса, и поэтому я принимаю его. К сожалению, моя реальная иерархия типов еще БОЛЕЕ сложна, и поэтому я застрял с приведением типов. Назовите это случаем чрезмерного упрощения вопроса и проблематичными ограничениями на обобщения. - person Nick Palmer; 28.03.2013
comment
@NickPalmer Если у вас есть время, чтобы составить дополнительный вопрос, я уверен, что людям будет интересно. - person Paul Bellora; 28.03.2013

Или вы можете сделать S универсальным:

interface SInt<A,B> {}
class Handler<T extends Root, S extends SInt<T, Middle>>{}
person janek    schedule 06.01.2014