代码之家  ›  专栏  ›  技术社区  ›  Michał Ziober

泛型和where子句

  •  2
  • Michał Ziober  · 技术社区  · 15 年前

    在。NET,我可以这样做:

    public static T[] CreateAndFillArray<T>(int size) where T : new()
    {
       T[] array = new T[size];
       for (int i = size - 1; i >= 0; i--)
           array[i] = new T();
       return array;
    }
    

    如何在Java中实现它?

    5 回复  |  直到 15 年前
        1
  •  11
  •   ChssPly76    15 年前

    除非将T作为参数传入,否则无法在java中创建泛型“T”类型的数组。

    public static <T> T[] createAndFillArray(Class<T> cls, int size) {
      T[] result = (T[]) Array.newInstance(cls, size);
      for (int i=0; i<size; i++) {
        result[i] = cls.newInstance();
      }
      return result;
    }
    
        2
  •  3
  •   Steven Schlansker    15 年前

    这是因为在运行时,泛型类型丢失(“擦除”),无法恢复。

    是否有不能使用的原因,例如,new ArrayList<T>()?

        3
  •  3
  •   Yishai    15 年前

    Java没有等效的构造。在包含构造函数的类上没有编译时安全性。

    public static <T> T[] createAndFillArray(T sampleObject, int size) throws Exception {
            Class<T> klass = sampleObject.getClass();
            T[] arr = (T[]) Array.newInstance(klass, size);
            for (int i = 0; i < size; i++) {
                arr[i] = klass.newInstance();
            }
            return arr;
    }
    

    上述方法可以工作,但如果没有公共无参数构造函数,则会引发异常。您无法让编译器强制存在一个。

    编辑:ChssPly76抢先一步,所以我修改了上面的代码,给出了一个示例,其中您传入了一个实际的对象示例,只是为了演示它是如何完成的。通常在这种情况下,您会传入类,因为sampleObject不会在数组中结束。

        4
  •  1
  •   TofuBeer    15 年前

    您可以使用此想法修复其他答案中缺少编译时检查的问题:

    import java.lang.reflect.Array;
    
    public class Main
    {
        public static void main(String[] args)
        {
            final String[] array;
    
            array = createAndFillArray(String.class, 10, new StringCreator());
    
            for(final String s : array)
            {
                System.out.println(s);
            }
        }
    
        public static <T> T[] createAndFillArray(final Class<T>   clazz,
                                                 final int        size,
                                                 final Creator<T> creator)
        {
            T[] result = (T[]) Array.newInstance(clazz, size);
    
            for (int i=0; i<size; i++)
            {
                result[i] = creator.newInstance();
            }
    
            return result;
        }
    }
    
    interface Creator<T>
    {
        T newInstance();
    }
    
    class StringCreator
        implements Creator<String>
    {
        public String newInstance()
        {
            // not the best example since String is immutable but you get the idea
            // you could even have newInstance take an int which is the index of the 
            // item being created if that could be useful (which it might).
            return ("hello");
        }
    }
    

    这实际上比您描述的C#方式更灵活,因为您可以根据需要控制构造函数,而不是简单地调用无参数构造函数。

        5
  •  0
  •   Ken Bloom    15 年前

    Scala确实如此,但它比实现适当的接口慢得多(因为它在内部使用反射来进行函数调用)。Scala不允许对对象构造函数的形式设置约束。JVM使用类型擦除,因此泛型代码实际上不知道它操作的是什么类型,因此它无论如何也不能构造这种类型的新对象。