在Java中将对象转换为可比较对象

5

这里有一个通用的方法:

public static <T extends Comparable<T>> T[] function(T[] a)
{
    Object[] m = new Object[2];

    /* some work here */

    return (T[]) m;
}

抛出了一个 ClassCastException,这是什么问题?

1
精确的堆栈跟踪是什么?同时,请发布引发异常的代码。 - Buhake Sindi
你正在以C#泛型的方式使用Java泛型。 - schlingel
1
@Elite - 我真的怀疑没有堆栈跟踪或异常,因为代码无法编译。 - Ted Hopp
6个回答

4

一个Object数组不是任何Object子类的数组。你面临的是Java泛型的限制之一:你不能创建一个泛型数组。参见这个线程中的方法可以解决这个问题。


但我们可以编写这样的代码: E[] array = (E[]) new Object[10]; //虽然会产生警告 这与代码中的内容是相同的,不是吗? - Majid Azimi
如果你使用-Xlint:unchecked编译,你会收到一个警告。除非EObject,否则在运行时你将不会满意结果。 - Ted Hopp

3

Object不是可比较的. 您需要定义您的数组为可比较类型。

由于您正在传递一个数组,因此您可以使用该数组的类型:

T[] m = Array.newInstance(a.getClass().getComponentType(), 2);

当然,您需要将Comparable对象放入其中。


那么什么是deference?Array.newInstance创建新的数组并返回Object[],然后我们将其转换为T[]。这就是我在代码中所做的。 - Majid Azimi
1
重要的部分是将可比较的对象放入数组中。newInstance 只是保存一些强制转换。 - Bozho
1
@Majid 这里使用的 Array.newInstance 将创建一个与输入相同类的新数组。在 Java 中,具有不同组件类型的数组之间存在差异,Object[] 和 Comparable[] 是两个不同的类。如果您比较两种不同类型的数组上 getClass 的结果,很容易看出这一点。由于 Object 不是与您的泛型 T 相同的类型(并且永远不会是),因此您将始终收到 ClassCastException。 - Andreas Holstenson
对象是所有类的超类。为什么我们不能将不同类的数组分配给它?另一个问题是为什么 E[] e = (E[]) new Object[3] 起作用,但 Object[] o = new Object[3] 然后 E[] e = (E[]) o 不起作用?它们做了相同的事情吗?不是吗? - Majid Azimi

3
你在这里有两个不同的问题。
首先,只需删除泛型并查看没有泛型的代码(这是编译时所擦除的内容):
public static Comparable[] function(Comparable[] a)
{
    Object[] m = new Object[2];

    /* some work here */

    return (Comparable[]) m;
}

你不能将实际运行时类为Object[]的对象转换为Comparable[]。就是这样。
其次,即使你重写代码创建一个Comparable[]而不是Object[]
public static <T extends Comparable<T>> T[] function(T[] a)
{
    Comparable[] m = new Comparable[2];

    /* some work here */

    return (T[]) m;
}

即使这样,它仍然不会起作用。在此函数内部不会抛出ClassCastException。但是,在调用此函数的任何代码中都会抛出它。例如:

String[] foo = function(new String[0]);

当你擦除类型时,会抛出ClassCastException异常,因为编译器会在泛型方法返回的内容上进行强制类型转换:

String[] foo = (String[])function(new String[0]);

您不能将实际类为Comparable[]的对象转换为String[]


当您询问那些说Array.newInstance()是在运行时创建一个已知类数组的方法的人“有什么区别”时,区别在于Array.newInstance()返回的对象的''实际、运行时''类型为Whatever[],其中“Whatever”是传递给它的类对象的类。静态值(编译时类型)为Object[]并不重要;实际运行时类型才是重要的。


当您说“另一个问题是为什么E[] e = (E[]) new Object[3]有效”时,您可能会忽略几个要点。首先,只有在E声明为<E><E extends Object>时才有效,即E的下限为Object。其次,这基本上是一个谎言(在实现通用集合等多个方面很方便,但您必须理解为什么它很危险);严格来说,当E不是Object时,您''不应该''能够从实际类型为Object[]的对象转换为E[]。它之所以“有效”,是因为在E的范围内,E被擦除了,因此我们无法检查转换。但是如果您尝试将该对象作为E[]返回给外部世界,您将以同样的方式获得ClassCastException。


2

实际上,你不能将对象数组强制转换为可比较的数组。这是没有意义的。编译器为什么会允许这样做呢?此外,例如,Integer类实现了Comparable接口,但你不能将Comparable数组强制转换为Integer数组。


0

这是你想要做的事情:

public static <T extends Comparable<T>> T[] function(final T[] a) {
    final T[] m = (T[]) Array.newInstance(a.getClass().getComponentType(), 2);

    /* some work here */

    return m;
}

0

T extends Comparable 表示方法参数(在本例中为 T)应该从 Comparable 继承。因此,当您尝试进行以下转换时

(T[]) m;

您正在尝试将Object[]强制转换为Comparable[](或任何扩展Comparable的内容)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接