Convert a generic list to an array

前端 未结 13 1304
隐瞒了意图╮
隐瞒了意图╮ 2020-12-05 17:13

I have searched for this, but unfortunately, I don\'t get the correct answer.

class Helper {
    public static  T[] toArray(List list) {
           


        
13条回答
  •  清歌不尽
    2020-12-05 17:33

    This gist that I wrote gives a good solution to this problem.

    Following siegi's suggestion on Atreys' answer, I wrote a constructor which finds the "nearest common ancestor" (NCA) class and uses that class to create the array. If checks for nulls and if the provided Collection is length 0 or all nulls, the default type is Object. It totally ignores Interfaces.

    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;
    
    public class FDatum {
    
      public T[] coordinates;
    
      // magic number is initial size -- assume <= 5 different classes in coordinates
      public transient HashSet classes = new HashSet(5);
    
      public FDatum (Collection 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 classes = new ArrayList(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 coordslist = new ArrayList(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;
      }
    
    }
    

    Here are some examples of using it in jshell ("unchecked" class warnings removed for brevity):

    jshell> FDatum d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3)))
    class java.lang.Double
    NCA: class java.lang.Double
    d ==> com.nibrt.fractal.FDatum@9660f4e
    
    jshell> d.coordinates
    $12 ==> Double[2] { 1.0, 3.3 }
    
    jshell> d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3, (byte)7)))
    class java.lang.Byte
    class java.lang.Double
    NCA: class java.lang.Number
    d ==> com.nibrt.fractal.FDatum@6c49835d
    
    jshell> d.coordinates
    $14 ==> Number[3] { 1.0, 3.3, 7 }
    
    jshell> d = new FDatum(new ArrayList(Arrays.asList((double)1, (Double)3.3, (byte)7, "foo")))
    class java.lang.Byte
    class java.lang.Double
    class java.lang.String
    NCA: class java.lang.Object
    d ==> com.nibrt.fractal.FDatum@67205a84
    
    jshell> d.coordinates
    $16 ==> Object[4] { 1.0, 3.3, 7, "foo" }
    

提交回复
热议问题