Вы можете избежать дублирования хранилища, если скопируете данные в список или массив, отсортированный по типам элементов. Затем, поскольку все элементы одного и того же типа являются последовательными элементами, вы можете использовать определенные c подпоследовательности, когда требуются подтипы:
Collection<A> data = externalSource();
// preparation step
class State<T> {
final Class<T> type;
int s, e;
List<?> list;
State(Class<T> c) {
type = c;
}
@SuppressWarnings("unchecked") <U> List<U> as(Class<U> c) {
if(c != type) throw new ClassCastException(c+" != "+type);
return (List<U>)list;
}
}
Map<Class<? extends A>,State<?>> tmp = new HashMap<>();
for(A a: data) tmp.computeIfAbsent(a.getClass(), State::new).s++;
int size = 0;
for(State<?> s: tmp.values()) {
int next = s.s;
s.s = s.e = size;
size += next;
}
A[] all = new A[size];
for(A a: data) all[tmp.get(a.getClass()).e++] = a;
List<A> listOfAll = Arrays.asList(all);
for(State<?> s: tmp.values())
s.list = listOfAll.subList(s.s, s.e);
// now, all lists are available, listOfAll for all As and:
List<B> listOfB = tmp.get(B.class).as(B.class);
List<C> listOfC = tmp.get(C.class).as(C.class);
List<D> listOfD = tmp.get(D.class).as(D.class);
List<E> listOfE = tmp.get(E.class).as(E.class);
System.out.println("B: "+listOfB+",\nC: "+listOfC+",\nD: "+listOfD+",\nE: "+listOfE);
Это выполняет сортировку с подсчетом в массив A[] all
, тогда все списки создаются как view в массиве, не имея собственного хранилища. Исходную коллекцию можно отбросить, оставив ее для сборки мусора.
Существует одна неизбежная непроверенная операция, но обратите внимание, что она имеет явную проверку времени выполнения для обеспечения безопасности, предполагая инициализацию код, показанный выше.
Этот код легко применим к другому количеству подклассов.
Демо на Ideone