Created
May 13, 2018 09:26
-
-
Save awwsmm/393cbc09c21d9c5d90652305a7ab88ba to your computer and use it in GitHub Desktop.
Convert generic Java Collection to a (sort of) generic array
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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