Ответ 1
Невозможно наложить такое ограничение времени компиляции. Типичные типовые параметры - это stand-ins для ссылочных типов; они не делают различий между типами классов и типами интерфейсов. Тот факт, что дополнительные ограничения в объявлении параметра типа должны быть типами интерфейсов, является просто случайным - ваша стратегия использовать это как средство для приведения типа в качестве интерфейса была умной, но она была побеждена ограничением, которое вводит параметры не может использоваться в нескольких границах.
Ваши единственные варианты - установить для проверки времени выполнения, используя Class.isInterface()
, как Louis Wasserman указали, или оставить его вызывающему абоненту, чтобы он отвечал за то, что он передает. В любом случае, убедитесь, что вы четко документируете методы ожидания и поведение.
B
предназначен для подстановки подстановочного знака, так что клиент может получить один объект, который является какSomeClass
, так иA
, без необходимости делать кастинг на основе доверия. У клиента не будет доступа к имени фактического класса, который реализуетSomeClass
иA
Это кажется мне противоречием. Нет смысла объявлять B
, если вызывающий абонент не может знать, что он оценивает. Помните: вызывающий объект общего метода предоставляет свои аргументы типа. Таким образом, вызывающий абонент, принимающий решение B
без каких-либо оснований, может только угадывать - и это никогда не может быть безопасным по типу.
Кажется, что вы действительно хотите, чтобы ваш метод возвращался, это какой-то тип, который является как SomeClass
, так и A
, но это сложно, потому что они не имеют общего супертипа:
public static <A> SomeClass&A makeSomeClass(A thing) {...}
(это бессмысленный синтаксис только для демонстрационных целей)
В качестве обходного пути рассмотрите альтернативные способы представления как a SomeClass
, так и некоторого типа интерфейса. Например, интерфейсы-кандидаты могут иметь общий метод для возврата SomeClass
:
public interface IsSomeClass {
SomeClass asSomeClass();
}
public interface Foo extends IsSomeClass { }
Реализация asSomeClass
на самом деле просто вернет this
. Тогда вы можете сделать:
public static <A extends IsSomeClass> A makeSomeClass(Class<A> type) {...}
И вызывающий объект этого метода сможет использовать возвращаемый объект как тип:
final Foo foo = makeSomeClass(Foo.class);
final SomeClass someClass = foo.asSomeClass();
Если сами интерфейсы не могут быть изменены, другой вариант заключается в том, чтобы вместо этого использовать класс-оболочку и состав:
final class SomeClassWrapper<A> {
private final SomeClass someClass;
private final A a;
//constructor and getters, etc.
}
И ваш метод вернет экземпляр оболочки вместо этого, назначив экземпляр реализации как SomeClass
, так и A
:
public static <A> SomeClassWrapper<A> makeSomeClass(Class<A> type) {...}