Skip to content

Instantly share code, notes, and snippets.

@awwsmm
Created May 13, 2018 09:26
Show Gist options
  • Save awwsmm/393cbc09c21d9c5d90652305a7ab88ba to your computer and use it in GitHub Desktop.
Save awwsmm/393cbc09c21d9c5d90652305a7ab88ba to your computer and use it in GitHub Desktop.
Convert generic Java Collection to a (sort of) generic array
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Array;
import java.util.Iterator;
// this class has two constructors:
// 1. takes a generic array and assigns it to a generic array
// 2. takes a generic collection and assigns it to a "generic" array
// "generic" because array class is actually most specific (nearest) common ancestor class (NCA)
// try something like:
// FDatum d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3)))
// FDatum d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3, (byte)7)))
// FDatum d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3, (byte)7, "foo")))
public class FDatum<T> {
public T[] coordinates;
// magic number is initial size -- assume <= 5 different classes in coordinates
public transient HashSet<Class> classes = new HashSet<Class>(5);
public FDatum (Collection<T> coordinates) {
// to convert a generic collection to a (sort of) generic array,
// we need to bend the rules:
// 1. default class T is Object
// 2. loop over elements in Collection, recording each unique class:
// a. if Collection has length 0, or
// if all elements are null, class T is Object
// b. otherwise, find most specific common superclass, which is T
// record all unique classes in coordinates
for (T t : coordinates) this.classes.add(t.getClass());
// convert to list so we can easily compare elements
List<Class> classes = new ArrayList<Class>(this.classes);
// nearest common ancestor class (Object by default)
Class NCA = Object.class;
// set NCA to class of first non-null object (if it exists)
for (int ii = 0; ii < classes.size(); ++ii) {
Class c = classes.get(ii);
if (c == null) continue;
NCA = c; break;
}
// if NCA is not Object, find more specific subclass of Object
if (!NCA.equals(Object.class)) {
for (int ii = 0; ii < classes.size(); ++ii) {
Class c = classes.get(ii);
if (c == null) continue;
// print types of all elements for debugging
System.out.println(c);
// if NCA is not assignable from c,
// it means that c is not a subclass of NCA
// if that is the case, we need to "bump up" NCA
// until it *is* a superclass of c
while (!NCA.isAssignableFrom(c))
NCA = NCA.getSuperclass();
}
}
// nearest common ancestor class
System.out.println("NCA: " + NCA);
// create generic array with class == NCA
T[] coords = (T[]) Array.newInstance(NCA, coordinates.size());
// convert coordinates to an array so we can loop over them
ArrayList<T> coordslist = new ArrayList<T>(coordinates);
// assign, and we're done!
for (int ii = 0; ii < coordslist.size(); ++ii)
coords[ii] = coordslist.get(ii);
// that's it!
this.coordinates = coords;
}
public FDatum (T[] coordinates) {
this.coordinates = coordinates;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment