你可以将一个 int 数组传递给 java 中的泛型方法吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/788433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:46:48  来源:igfitidea点击:

Can you pass an int array to a generic method in java?

javagenerics

提问by blank

I'm playing around with some code katas and trying to get a better understanding of java generics at the same time. I've got this little method that prints arrays like I like to see them and I have a couple of helper methods which accept an array of 'things' and an index and returns the array of the 'things' above or below the index (it's a binary search algorithm).

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

Two questions,

两个问题,

#1 Can i avoid the cast to T in splitBottom and splitTop? It doesn't feel right, or I'm going about this the wrong way (don't tell me to use python or something .. ;) )

#1 我可以避免在 splitBottom 和 splitTop 中转换为 T 吗?感觉不对,或者我以错误的方式解决这个问题(不要告诉我使用 python 或其他东西 .. ;) )

#2 Do I have to write seperate methods to deal with primitive arrays or is there a better solution?

#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};
        // ???
    }
}

回答by Peter Lawrey

Generics don't handle primitives in a consistent fashion. This is because Generics are not like templates in C++, it is just a compile time addition to a single class.

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

When generic are compiled, you end up with Object[] in the above example as the implementing type. As int[] and byte[] etc, do not extend Object[] you cannot use them inter-changeably even if the code involved would be identical (again generics are not templates)

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

The only class int[] and Object[] share is Object. You can write the above methods Object as the type (see System.arraycopy, Array.getLength, Array.get, Array.set)

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

回答by newacct

1 Can i avoid the cast to T in splitBottom and splitTop? It doesn't feel right, or I'm going about this the wrong way (don't tell me to use python or something .. ;) )

1 我可以避免在 splitBottom 和 splitTop 中转换为 T 吗?感觉不对,或者我以错误的方式解决这个问题(不要告诉我使用 python 或其他东西 .. ;) )

Not only can you not avoid it, but you shouldn't do it. In Java, different types of arrays are actually different runtime types. An array that was created as an Object[]cannot be assigned to a variable of AnythingElse[]. The cast there will not fail immediately, because in generics the type T is erased, but later it will throw a ClassCastException when code tries it to use it as a Something[] as you promised them, but it is not.

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

The solution is to either use the Arrays.copyOf...methods in Java 6 and later, or if you are using an earlier version of Java, use Reflection to create the correct type of array. For example,

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

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

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

2 Do I have to write seperate methods to deal with primitive arrays or is there a better solution?

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

It is probably best to write separate methods. In Java, arrays of primitive types are completely separate from arrays of reference types; and there is no nice way to work with both of them.

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

It is possible to use Reflection to deal with both at the same time. Reflection has Array.get()and Array.set()methods that will work on primitive arrays and reference arrays alike. However, you lose type safety by doing this as the only supertype of both primitive arrays and reference arrays is Object.

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

回答by Apocalisp

Java does not allow the construction of generic arrays in a type-safe manner. Use a generic sequence type instead (such as java.util.List, for example).

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

Here's how I would write your test program, using a generic container class fj.data.Stream:

下面是我将如何使用通用容器类编写您的测试程序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)));

  // ...
}

回答by waxwing

Question 1: Casting arrays doesn't work like you expect. A String is an Object, but a String array isn't an Object array.

问题 1:转换数组不像您期望的那样工作。字符串是对象,但字符串数组不是对象数组。

Try to use something like:

尝试使用类似的东西:

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

Question 2: For arrays of primitives my function obviously doesn't work either. There is no elegant solution to it - look at for example the Arrays library which have several copies of essentially the same method for each primitive array type.

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

回答by Uri

You've got two problems with what you are trying to accomplish.

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

First of all, you are trying to use primitive types, which do not actually inherit from Object. This will mess up things. If you really need to do this, explicitly use Integer rather than int, etc.

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

The second and greater problem is that Java generics have type erasure. This means that at runtime, you cannot actually refer to the type of the generic. This was done to allow you to mix generic-supporting and non generic-supporting code, and ended up (IMHO) being a major source of headache for Java developers and another proof that generics should have been in Java from day 1. I suggest you read the part in the tutorialabout it, it will make this issue clearer.

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

回答by Roald

You will probably have to wrap the primitives into corresponding collections.

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

I also suggest to take a look to Trove primitive collections (http://trove.starlight-systems.com). This is unrelated to your generics question, but may be quite interesting.

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