Pergunta

Eu acho que deve haver algo sutil acontecendo aqui que eu não sei sobre. Considere o seguinte:

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

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

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

Suponha que o seu método principal contém o seguinte:

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

Você vai ter uma CastClassException com o java.lang.Object mensagem não pode ser convertido para java.lang.Double.

Alguém pode me dizer por quê? O meu entendimento de ClassCastException é que ela é lançada quando você tentar converter um objeto para um tipo que não pode ser escalado. Ou seja, a uma subclasse de que não é uma instância (para citar a documentação). por exemplo:.

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

E parece que eu posso fazer isso. Se a era apenas um T em vez de um T[] array, podemos obter a e lançá-lo sem nenhum problema. Por que matrizes quebrar isso?

Graças.

Foi útil?

Solução

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

Quando você usa esta versão da classe Foo genérico, em seguida, para a variável membro a, o compilador está essencialmente tomando esta linha:

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

e substituindo T com Double para obter este:

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

Você não pode lançar a partir de objetos para casal, daí o ClassCastException.

Update e Esclarecimento: Na verdade, após a execução de um código de teste, a ClassCastException é mais sutil do que isso. Por exemplo, este método principal vai funcionar bem sem qualquer exceção:

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

O problema ocorre quando você tenta f.getA() atribuir a uma referência do tipo Double[]:

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

Isso ocorre porque o tipo de informações sobre a variável de membro a é apagada durante a execução. Genéricos só fornecer tipo-segurança no tempo de compilação (eu estava de alguma forma ignorar isso no meu post inicial). Então o problema não é

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

porque em tempo de execução este código é realmente

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

O problema ocorre quando o resultado de getA() método, que em tempo de execução, na verdade, retorna um Object[], é atribuído a uma referência do tipo Double[] -. Esta declaração lança a ClassCastException porque objeto não pode ser convertido para Double

Update 2 : "por que matrizes quebrar este" para responder à sua pergunta final A resposta é porque a especificação da linguagem não suporta a criação matriz genérica. Veja este post fórum para mais -, a fim de ser compatível, nada se sabe sobre o tipo de T em tempo de execução.

Outras dicas

Pode haver alguns pequenos erros no @ de MattB explicação.

O erro é não

java.lang.Object não pode ser convertido para java.lang.Double.

É:

[Ljava.lang.Object; não pode ser convertido para [Ljava.lang.Double

O [L significa uma matriz. Ou seja, o erro é que um array de objetos não pode ser convertido para uma matriz de duplo. Este é o mesmo caso como a seguir:

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

Esta é, obviamente, não é permitido.

Para a sua questão da criação de typesafe matrizes, outra alternativa é a exceto um objeto de classe em init e uso 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: Obrigado pela resposta! Muito útil.

Eu encontrei uma solução alternativa para os interessados: dar o método Geta um array inicializado para preencher. Dessa forma, a informação tipo está disponível.

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

Em seguida, para o seu método principal:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top