Pregunta

Creo que debe haber algo sutil que no sé acerca de.Considere lo siguiente:

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

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

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

Supongamos que el principal método contiene lo siguiente:

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

Usted recibirá una CastClassException con el mensaje java.lang.Object no se puede convertir a java.lang.Double.

¿Alguien puede decirme por qué?Mi comprensión de la ClassCastException es la que se produce cuando intenta convertir un objeto a un tipo que no se puede lanzar.Es decir, a una subclase de que no es una instancia (cita de la documentación).por ejemplo:

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

Y parece que me puede hacer esto.Si a era sólo un T en lugar de una matriz T[], podemos conseguir a y lo echó sin problema.¿Por qué las matrices de romper este?

Gracias.

¿Fue útil?

Solución

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

Cuando se utiliza esta versión de la clase genérica Foo, a continuación, para la variable miembro a, el compilador está esencialmente tomando esta línea:

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

y la sustitución de T con Double Para conseguir esto:

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

No se puede lanzar desde el objeto al doble, de ahí el ClassCastException.

Actualizar y Aclaración: En realidad, después de ejecutar algún código de prueba, el ClassCastException es más sutil que esto. Por ejemplo, este método principal funcionará bien sin ningún tipo de excepción:

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

El problema se produce cuando se intenta asignar f.getA() a una referencia de tipo Double[]:

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

Esto es porque el tipo de información acerca de la variable miembro getA() se borra en tiempo de ejecución. Los genéricos sólo proporcionan seguridad de tipos a en tiempo de compilación (de alguna manera estaba haciendo caso omiso de esto en mi post inicial). Así que el problema no es

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

porque en tiempo de ejecución de este código es realmente

<*>

El problema se produce cuando el resultado del método Object[], que en tiempo de ejecución en realidad devuelve un <=>, es asignado a una referencia de tipo <=> - esta declaración los tiros ClassCastException debido a objeto no se puede convertir en doble <. / p>

Actualización 2 : para responder a su pregunta final "¿por qué matrices romper esto?" La respuesta es porque la especificación del lenguaje no admite la creación de la matriz genérica. Ver este mensaje en el foro para más - con el fin de ser compatible hacia atrás, no se sabe nada sobre el tipo de T en tiempo de ejecución.

Otros consejos

Puede haber algunos pequeños errores en la explicación de @ MattB.

El error es no

  

java.lang.Object no se puede convertir a java.lang.Double.

Es:

  

[Ljava.lang.Object; No se puede lanzar a [Ljava.lang.Double

El [L significa una matriz. Es decir, el error es que un array de objetos no se puede convertir a una matriz de doble. Este es el mismo caso como sigue:

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

Esto es, obviamente, no está permitido.

Para su tema de la creación de matrices typesafe, otra alternativa es menos que un objeto de clase en init y utilizar 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 @ Matt: Gracias por la respuesta! Muy útil.

He encontrado una solución para aquellos interesados: dar el método Geta una matriz inicializada para poblar. De esta manera la información de tipo está disponible.

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;
  }
}

A continuación, para su principal método:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top