【问题标题】:Can you pass an int array to a generic method in java?您可以将 int 数组传递给 java 中的泛型方法吗?
【发布时间】:2009-04-25 07:13:38
【问题描述】:

我正在玩一些代码 katas 并试图同时更好地理解 java 泛型。我有这个小方法可以打印我喜欢看到的数组,我有几个辅助方法,它们接受一个“事物”数组和一个索引,并返回索引上方或下方的“事物”数组(它是一种二分搜索算法)。

两个问题,

#1 我可以避免在 splitBottom 和 splitTop 中强制转换为 T 吗?感觉不对,或者我用错了方法(不要告诉我使用 python 或其他东西.. ;))

#2 我必须编写单独的方法来处理原始数组还是有更好的解决方案?

public class Util {

    public static <T> void print(T[] array) {
        System.out.print("{");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]);
            if (i < array.length - 1) {
                System.out.print(", ");
            }
        }
        System.out.println("}");
    }

    public static <T> T[] splitTop(T[] array, int index) {
        Object[] result = new Object[array.length - index - 1];
        System.arraycopy(array, index + 1, result, 0, result.length);
        return (T[]) result;
    }

    public static <T> T[] splitBottom(T[] array, int index) {
        Object[] result = new Object[index];
        System.arraycopy(array, 0, result, 0, index);
        return (T[]) result;
    }

    public static void main(String[] args) {

        Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        print(integerArray);
        print(splitBottom(integerArray, 3));
        print(splitTop(integerArray, 3));

        String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
        print(stringArray);
        print(splitBottom(stringArray, 3));
        print(splitTop(stringArray, 3));

        int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        // ???
    }
}

【问题讨论】:

    标签: java generics


    【解决方案1】:

    泛型不会以一致的方式处理基元。这是因为泛型不像 C++ 中的模板,它只是对单个类的编译时添加。

    编译泛型时,您最终会使用上面示例中的 Object[] 作为实现类型。如 int[] 和 byte[] 等,不要扩展 Object[] 即使涉及的代码相同,也不能互换使用它们(再次泛型不是模板)

    唯一的类 int[] 和 Object[] 共享是 Object。可以把上面的方法Object写成类型(见System.arraycopy, Array.getLength, Array.get, Array.set)

    【讨论】:

      【解决方案2】:

      1 我可以避免在 splitBottom 和 splitTop 中强制转换为 T 吗?它没有 感觉不错,或者我要解决这个问题 错误的方式(不要告诉我使用 python 什么的 .. ;) )

      你不仅不能避免它,而且你不应该这样做。在 Java 中,不同类型的数组实际上是不同的运行时类型。创建为Object[] 的数组不能分配给AnythingElse[] 的变量。那里的转换不会立即失败,因为在泛型中类型 T 被删除,但稍后当代码尝试将它用作您承诺的Something[]时,它会抛出 ClassCastException,但事实并非如此。

      解决方案是在 Java 6 及更高版本中使用 Arrays.copyOf... 方法,或者如果您使用的是早期版本的 Java,请使用反射来创建正确类型的数组。例如,

      T[] 结果 = (T[])Array.newInstance(array.getClass().getComponentType(), size);

      2 我必须编写单独的方法来处理原始数组还是 有更好的解决方案吗?

      最好编写单独的方法。在 Java 中,原始类型数组与引用类型数组是完全分开的;并且没有很好的方法可以同时使用它们。

      可以使用反射同时处理两者。反射具有Array.get()Array.set() 方法,它们可以用于原始数组和引用数组。但是,这样做会失去类型安全性,因为原始数组和引用数组的唯一超类型是 Object

      【讨论】:

        【解决方案3】:

        问题 1: 转换数组不像你期望的那样工作。 String 是 Object,但 String 数组不是 Object 数组。

        尝试使用类似的东西:

        public static <T> T[] splitTop(T[] array, int index) {
            T[] result = Arrays.copyOfRange(array, index + 1, array.length);
            return result;
        }
        

        问题 2: 对于基元数组,我的函数显然也不起作用。没有优雅的解决方案 - 看看 Arrays 库,它为每个原始数组类型提供了几个基本相同的方法的副本。

        【讨论】:

        • 泛型无法做到这一点——这会导致不兼容的类型错误。
        【解决方案4】:

        Java 不允许以类型安全的方式构造泛型数组。请改用通用序列类型(例如java.util.List)。

        以下是我将如何使用通用容器类fj.data.Stream 编写您的测试程序:

        import fj.data.Stream;
        import static fj.data.Stream.range;
        
        // ...
        
        public int[] intArray(Stream<Integer> s) {
          return s.toArray(Integer.class).array()
        }
        
        public static void main(String[] args) {
          Stream<Integer> integerStream = range(1, 10);
          print(intArray(integerStream));
          print(intArray(integerStream.take(3)));
          print(intArray(integerStream.drop(3)));
        
          // ...
        }
        

        【讨论】:

          【解决方案5】:

          你想要完成的工作有两个问题。

          首先,您尝试使用原始类型,它们实际上并不从 Object 继承。这会把事情搞砸。如果确实需要这样做,请显式使用 Integer 而不是 int 等。

          第二个也是更大的问题是 Java 泛型具有类型擦除。这意味着在运行时,您实际上无法引用泛型的类型。这样做是为了让您可以混合支持泛型和非泛型支持的代码,最终(恕我直言)成为 Java 开发人员头疼的主要来源,并证明泛型从一开始就应该在 Java 中使用。我建议您阅读tutorial 中关于它的部分,它将使这个问题更加清晰。

          【讨论】:

            【解决方案6】:

            您可能必须将原语包装到相应的集合中。

            我还建议看看 Trove 原始集合 (http://trove.starlight-systems.com)。这与您的泛型问题无关,但可能很有趣。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-05-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-12-16
              相关资源
              最近更新 更多