Question

Je pense qu'il doit y avoir quelque chose de subtil se passe ici que je ne sais pas. Considérez ce qui suit:

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

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

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

Supposons que votre principale méthode contient les éléments suivants:

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

Vous obtiendrez un message avec CastClassException ne peut pas être java.lang.Object jeté à java.lang.Double.

Quelqu'un peut-il me dire pourquoi? Ma compréhension de c'est qu'il ClassCastException est jeté lorsque vous essayez de jeter un objet à un type qui ne peut pas être casté. Autrement dit, à une sous-classe dont il n'est pas une instance (pour citer la documentation). par exemple:.

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

Et il semble que je peux le faire. Si était juste un a au lieu d'un T tableau T[], nous pouvons obtenir et de le jeter <=> sans problème. Pourquoi les tableaux briser ce?

Merci.

Était-ce utile?

La solution

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

Lorsque vous utilisez cette version de la classe générique Foo, puis pour la variable membre a, le compilateur est essentiellement prend cette ligne:

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

et le remplacement par T pour obtenir ce Double:

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

Vous ne pouvez pas lancer d'objets en double, d'où le ClassCastException.

Mise à jour et clarification: En fait, après l'exécution d'un code de test, le ClassCastException est plus subtile que cela. Par exemple, cette méthode principale fonctionnera très bien sans exception:

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

Le problème se produit lorsque vous essayez d'assigner à une référence f.getA() de type Double[]:

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

En effet, le type d'informations sur la variable membre est effacé à getA() exécution. Generics ne fournissent que de sécurité de type à compilation (je ne tenait pas compte en quelque sorte dans mon premier post). Le problème est donc pas

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

parce que lors de l'exécution de ce code est vraiment

<*>

Le problème se produit lorsque le résultat de la méthode Object[], qui lors de l'exécution retourne en fait un <=>, est affecté à une référence de type <=> - cette déclaration lance le ClassCastException parce que l'objet ne peut pas être jeté à double <. / p>

Mise à jour 2 : pour répondre à votre dernière question: "Pourquoi les tableaux briser ce?" La réponse est parce que la spécification du langage ne prend pas en charge la création de tableau générique. Voir ce post forum pour plus - afin d'être rétrocompatible, on ne sait rien sur le type de T lors de l'exécution.

Autres conseils

Il peut y avoir quelques petites erreurs dans l'explication @ MattB.

L'erreur est pas

  

java.lang.Object ne peut pas être jeté à java.lang.Double.

Il est:

  

[Ljava.lang.Object; ne peut pas être jeté à [Ljava.lang.Double

[L signifie un tableau. Autrement dit, l'erreur est qu'un array d'objets ne peut pas être jeté à un tableau de double. Ce cas est le même que ce qui suit:

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

Ceci est évidemment pas permis.

Pour votre question de la création des réseaux de Typesafe, une autre alternative est à l'exception d'un objet de classe dans init et utiliser 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: Merci pour la réponse! Très utile.

J'ai trouvé une solution pour les personnes intéressées: donner la méthode Geta un tableau initialisées à remplir. De cette façon, les informations de type 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;
  }
}

Ensuite, pour la méthode principale:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top