你能把一个int数组传递给java中的generics方法吗?

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

两个问题,

#1我可以避免在splitBottom和splitTop中转换为T吗? 它感觉不对,或者我以错误的方式进行此操作(不要告诉我使用python或其他东西..;))

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

public class Util { public static  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[] 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[] 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}; // ??? } } 

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

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

唯一的类int []和Object []共享是Object。 您可以将上述方法Object作为类型编写(请参阅System.arraycopy,Array.getLength,Array.get,Array.set)

1我可以避免在splitBottom和splitTop中转换为T吗? 它感觉不对,或者我以错误的方式进行此操作(不要告诉我使用python或其他东西..;))

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

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

T [] result =(T [])Array.newInstance(array.getClass()。getComponentType(),size);

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

最好编写单独的方法。 在Java中,基本类型的数组与引用类型的数组完全分开; 并没有很好的方式来处理它们。

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

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

尝试使用类似的东西:

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

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

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

以下是我使用通用容器类fj.data.Stream编写测试程序的方法:

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

你要完成的任务有两个问题。

首先,您正在尝试使用原始类型,这些类型实际上并不从Objectinheritance。 这会弄乱事情。 如果你真的需要这样做,请明确使用Integer而不是int等。

第二个也是更大的问题是Javagenerics有类型擦除。 这意味着在运行时,您实际上无法引用generics的类型。 这样做是为了让你能够混合generics支持和非generics支持代码,并最终(恕我直言)成为Java开发人员头痛的主要来源,并且certificate了generics应该从第1天开始使用Java。我建议你阅读教程中关于它的部分,它将使这个问题更加清晰。

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

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