содержит ли коллекция тип
Допустим есть Class A и несколько классов наследников:
Class B extends A
Class C extends A
и т.д.
Я складываю, к примеру, в ArrayList все или некоторые из наследников.
Дальше мне нужно передать эту коллекцию в метод и если в ней содержатся не все наследники (2 из 2. как в моем примере или n изи n в общем случае), то метод не должен выполняться. То есть я должен проверить, что в коллекции содержатся все наследники. Как мне это сделать, пожалуйста, подскажите
Ответы (2 шт):
В зависимости от этапа, на котором вам следует решить задачу имеется, по крайней мере, два способа:
Проверка на этапе компиляции: (compile time)
На этапе компиляции данную задачу можно решить посредством применения Generic'ов: объявить коллекцию таким образом, чтобы туда априори не могли добавить экземпляры классов, отличных от A и его наследников (рассмотрим на примере List<A>):
class B extends A {}
class C extends A {}
class D {}
...
void initialMethod() {
List<A> list = new ArrayList<>();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new D()); // Error:(25, 18) java: incompatible types: D cannot be converted to A
callingMethod(list);
}
...
void initialMethod2() {
List<Object> list = new ArrayList<>();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new D());
callingMethod(list); // Error:(23, 20) java: incompatible types: java.util.List<java.lang.Object> cannot be converted to java.util.List<A>
}
...
void callingMethod(List<A> list) {
// непосредственная логика работы метода
}
Если же предполагается, что List может быть объявлен (тем, кто использует метод, в который передает коллекцию) без использования Generic'ов, то в таком случае компилятор выдаст warning, но ошибка этапа компиляции получена не будет, в таком случае придется решать проблему на этапе исполнения (см. ниже).
Проверка на этапе исполнения: (runtime)
На этапе исполнения данную задачу можно решить посредством применения рефлексии: пробежать всю коллекцию и проверить классы, используя какой-либо из способов рефлексии (классический instance of, либо объектный isAssignableFrom):
class B extends A {}
class C extends A {}
class D {}
...
void initialMethod2() {
List list = new ArrayList();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new D());
callingMethod(list);
}
...
void callingMethod(List list) {
for (Object item : list) {
if (item instanceof A) { // либо A.class.isAssignableFrom(item.getClass())
throw new Exception(""); // либо иной способ обработки
}
}
// непосредственная логика работы метода (поток исполнения дойдет до сюда, только если проверка выше прошла)
}
Update: (после пояснения/обновления вопроса)
Вариант решения через Enum и его наследников:
public class SomeTest {
enum MyEnum {
FIRST {
@Override
String someMethod() {
return name();
}
},
SECOND {
@Override
String someMethod() {
return name();
}
};
THIRD {
@Override
String someMethod() {
return name();
}
};
abstract String someMethod();
}
public static void main(String[] args) {
someMethod(EnumSet.of(MyEnum.FIRST, MyEnum.THIRD));
}
static void someMethod(Set<MyEnum> collection) {
if (collection.size() != MyEnum.values().length) {
throw new RuntimeException();
}
// ваша бизнес логика
}
}
Надо пробежаться циклом по всем элементам ArrayList и применить instanceof A к каждому элементу.
Если где то не сработает instanceof - бинго - вот он элемент, который не является потомком класса A