Я очень новичок в дженериках Java и типе Класс<> clazz, у меня есть интерфейс
public interface MyInterface {
void doSomething(String arg1);
}
который реализуется несколькими классами
class MyInterfaceImplFirst implements MyInterface {
private arg;
public MyInterfaceImplFirst(String arg) {
this.arg = arg;
}
@Override
void doSomething(String arg1) {
//...
}
}
class MyInterfaceImplSecond implements MyInterface {
private arg;
public MyInterfaceImplSecond(String arg) {
this.arg = arg;
}
@Override
void doSomething(String arg1) {
//...
}
}
У меня есть класс, который принимает Class<MyInterface> type
public class Dummy {
public void load(Class<MyInterface> clazz) {
//...
}
public static void main(String[] args) {
Dummy dummy = new Dummy();
//The below does not compile
dummy.load(MyInterfaceImplFirst.class);
}
}
Если я изменю метод загрузки на общественная пустая нагрузка (класс clazz), он будет работать нормально, может ли кто-нибудь сказать мне, как ограничить аргументы для метода загрузки только подтипами (импл) Мой интерфейс?
Проблема заключается в PECS (Producer-Extends, Consumer-Super). Учитывая List<Number>
, вы, конечно, можете вызвать .add(someDouble)
. Следовательно, List<Integer>
не можешь передается, когда требуется List<Number>
. Эта концепция «записи» просто не применяется к Class<X>
, но java не «знает» этого и, следовательно, не позволит вам передать Class<SomeImpl>
, когда требуется Class<TheInterface>
.
PECS — это неправильное название; он написан с точки зрения универсального типа (так, список, класс и т. д.). Если класс только производит материал и не будет потреблять ничего общего типа, как в данном случае, PECS указывает, что вы должны использовать extends
.
Следовательно, public void load<Class<? extends MyInterface> clazz)
— это то, что вам нужно.
Несколько заметок:
?
вместо этого.Class
обычно плохо. Есть вещи, которые может представлять Class
, например, int
(Class<?> c = int.class;
является допустимым java), которые не могут быть представлены дженериками (List<int>
не является допустимым java), и наоборот, дженерики могут представлять этот класс. У вас не может быть экземпляра java.lang.Class
, представляющего List<String>
(только List — необработанный тип). Class<List<String>>
не вещь; List<String>.class
не работает. List<List<String>>
работает.Class<? extends MyInterface>
- скорее всего это была ошибка. Вы не объяснили, почему вы решили, что вам это нужно. Скорее всего, правильный ответ — фабрика. Фабрика — это, по сути, абстракция для конструкторов.