我觉得一定有什么微妙的事情在这里,我不知道。考虑以下几点:

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA() {
    return a;
  }
}

假设你的主要方法包含以下内容:

Foo<Double> f = new Foo<Double>();
Double[] d = f.getA();

您将获得与消息CastClassException一个java.lang.Object不能转换为java.lang.Double

谁能告诉我为什么?我ClassCastException的理解是,当你尝试对象转换不能铸造类型被抛出。也就是说,到子类,它是不是一个实例(引用文档)。 e.g:

Object o = new Double(3.);
Double d = (Double) o; // Working cast
String s = (String) o; // ClassCastException

和它似乎我能做到这一点。如果a只是一个T而不是数组T[],我们可以得到a并投它没有问题。阵列为什么犯这个?

感谢。

有帮助吗?

解决方案

Foo<Double> f = new Foo<Double>();

当使用此版本的通用类Foo的,那么对于成员变量a,编译器基本上采取这一行:

private T[] a = (T[]) new Object[5];

和与T替换Double得到这样的:

private Double[] a = (Double[]) new Object[5];

可以不从Object转换为双,因此ClassCastException异常。

<强>更新和澄清:实际上,运行一些测试代码之后,ClassCastException异常比这更微妙。例如,该main方法将正常工作而没有任何异常:

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    System.out.println(f.getA());
}

当尝试给f.getA()到类型Double[]的基准时发生该问题

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    Double[] a2 = f.getA(); // throws ClassCastException
    System.out.println(a2);
}

这是因为关于成员变量a类型信息是在运行时被擦除。泛型只提供类型安全的编译时间的(我在某种程度上在我最初的帖子忽略这一点)。所以,问题是不

private T[] a = (T[]) new Object[5];

,因为在运行时这个代码是真的

private Object[] a = new Object[5];

当方法getA(),其在运行时实际返回的Object[]的结果,被分配给类型Double[]的基准时发生该问题 - 该语句抛出ClassCastException异常,因为对象不能被转换为双

更新2 :回答你的最后一个问题 “为什么阵列打破这个?”答案是因为语言规范不支持通用阵列的创建。 看到这个论坛的帖子更多 - 为了向后兼容,没有什么是已知的约的T在运行时类型。

其他提示

有可能在@ mattb的解释一些小错误。

的错误是

  

java.lang.Object中不能转换到java.lang.Double中。

有:

  

[Ljava.lang.Object;不能被转换为[Ljava.lang.Double

在[L装置的阵列。也就是说,错误是对象的阵列不能转换到双阵列。这是相同的情况下,如下:

Object[] oarr = new Object[10];
Double[] darr = (Double[]) oarr;

这显然是不允许的。

有关你创建类型安全阵列的问题,另一种选择是除A类对象在init和使用Array.newInstance:

import java.lang.reflect.Array;

class Foo<T> {
  private T[] a ;

  public Foo(Class<T> tclass) {
    a = (T[]) Array.newInstance(tclass, 5);
  }

  public T[] getA() {
    return a;
  }

  public static <T> Foo<T> create(Class<T> tclass) {
    return new Foo<T>(tclass);
  }
}

class Array1
{
  public static final void main(final String[] args) {
    Foo<Double> f = Foo.create(Double.class);
    Double[] d = f.getA();
  }


}

@马特B:感谢您的回答!非常有益的。

我发现对于那些有兴趣一种解决方法:给木屐方法初始化的数组来填充。这样的类型的信息是可用的。

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA(T[] holdA) {
    // Check whether holdA is null and handle it...then:
    holdA = (T[]) Array.newInstance(holdA.getClass().getComponentType(), a.length);
    System.arraycopy(a, 0, holdA, 0, a.length);
    return holdA;
  }
}

然后,对于你的主要方法:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top