содержит ли коллекция тип

Допустим есть Class A и несколько классов наследников:

Class B extends A
Class C extends A

и т.д.

Я складываю, к примеру, в ArrayList все или некоторые из наследников.

Дальше мне нужно передать эту коллекцию в метод и если в ней содержатся не все наследники (2 из 2. как в моем примере или n изи n в общем случае), то метод не должен выполняться. То есть я должен проверить, что в коллекции содержатся все наследники. Как мне это сделать, пожалуйста, подскажите


Ответы (2 шт):

Автор решения: StateItPrimitive

В зависимости от этапа, на котором вам следует решить задачу имеется, по крайней мере, два способа:

Проверка на этапе компиляции: (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();
        }

        // ваша бизнес логика
    }
}
→ Ссылка
Автор решения: Barmaley Red Star

Надо пробежаться циклом по всем элементам ArrayList и применить instanceof A к каждому элементу.

Если где то не сработает instanceof - бинго - вот он элемент, который не является потомком класса A

→ Ссылка