Frage

ich glaube, es hier etwas subtiler los sein muss, dass ich nicht kenne. Betrachten Sie das folgende:

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

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

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

Nehmen wir an, dass Ihre Hauptmethode enthält folgende Komponenten:

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

Sie erhalten eine CastClassException mit der Meldung java.lang.Object bekommen kann nicht auf java.lang.Double gegossen werden.

Kann mir jemand sagen, warum? Mein Verständnis von ClassCastException ist, dass es ausgelöst wird, wenn Sie versuchen, ein Objekt auf eine Art zu werfen, die nicht gegossen werden können. Das heißt, auf eine Unterklasse von denen es keine Instanz ist (in der Dokumentation zu zitieren). z.

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

Und es scheint, dass ich dies tun kann. Wenn a nur T anstelle eines Arrays T[] war, können wir a bekommen und es ohne ein Problem werfen. Warum diese Arrays brechen?

Danke.

War es hilfreich?

Lösung

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

Wenn Sie diese Version der generischen Klasse Foo, dann für die Membervariable a, der Compiler im Wesentlichen nimmt diese Zeile:

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

und Ersetzen T mit Double diese zu bekommen:

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

Sie können nicht von Objekt zu Double gegossen, damit der Classcast.

Update und Klarstellung: Eigentlich nachdem er einige Test-Code ausgeführt wird, der Classcast ist subtiler als diese. Zum Beispiel wird das Hauptverfahren ohne Ausnahme gut funktionieren:

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

Das Problem tritt auf, wenn Sie versuchen, f.getA() zu einer Referenz des Typs Double[] zuweisen:

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

Das ist, weil die Typ-Informationen über die Membervariable a zur Laufzeit gelöscht werden. Generics nur bietet Typsicherheit in Compiler- (ich irgendwie war das in meinem ersten Beitrag zu ignorieren). Das Problem ist also nicht

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

, weil während der Laufzeit dieser Code ist wirklich

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

Das Problem tritt auf, wenn das Ergebnis der Methode getA(), die tatsächlich zur Laufzeit eine Object[] zurückkehrt, zu einer Referenz des Typ Double[] zugeordnet ist - diese Aussage führt den Classcast weil Objekt nicht zu Doppel gegossen werden kann

.

Update 2 : Ihre letzte Frage zu beantworten: "Warum Arrays bricht das?" Die Antwort ist, weil die Sprachspezifikation nicht generische Array-Erstellung unterstützt. Sehen Sie in diesem Forum Beitrag für mehr - um rückwärts kompatibel zu sein, ist nichts bekannt über die Art der T zur Laufzeit.

Andere Tipps

Es kann einige kleine Fehler in der Erklärung des @ MattB sein.

Der Fehler ist nicht

  

java.lang.Object kann nicht auf java.lang.Double gegossen werden.

Es ist:

  

[Ljava.lang.Object; nicht auf [Ljava.lang.Double gegossen werden

[L bedeutet ein Array. Das heißt, der Fehler ist, dass ein array Gegenstände kann nicht auf ein Array von Doppel gegossen werden. Dies ist der gleiche Fall wie folgt vor:

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

Das ist natürlich nicht erlaubt.

Für Ihre Ausgabe typsichere Anordnungen zu schaffen, eine weitere Alternative ist es, ein Klassenobjekt in init auszunehmen und verwenden 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();
  }


}

@ Matt b: Danke für die Antwort! Sehr hilfreich.

gibt der getA Methode eine initialisierte Array zu füllen:

Ich habe eine Abhilfe für die Interessenten gefunden. Auf diese Weise der Typ Info zur Verfügung.

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

Dann für Ihre Hauptmethode:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top