1
votes

Créer un tableau de type générique de classe

Pour la classe, nous devons implémenter des structures de données en java sans utiliser celles déjà implémentées par défaut, donc non je ne peux pas utiliser les Lists . Auparavant, il y avait des situations où il était nécessaire de créer un tableau de type générique T et le suivant fonctionne sans problème:

class Thing<T> { }

class Test<T> {
  private Thing<T>[] array;

  @SuppressWarnings("unchecked")
  public Test(int sz) {
    array = (Thing<T>[]) new Object[sz];
  }

  public static void main(String[] args) {
    Test<Object> test = new Test<>(1);
  }
}

Maintenant au lieu d'un tableau de type T , il fallait créer un tableau de type Thing où Thing est une classe ... La même approche donne une erreur d'exécution (java.lang.ClassCastException):

class Test<T> {
  private T[] array;

  @SuppressWarnings("unchecked")
  public Test(int sz) {
    array = (T[]) new Object[sz];
  }

  public static void main(String[] args) {
    Test test = new Test(1);
  }
}

Que peut-on faire pour le deuxième cas?


11 commentaires

Au lieu de faire array = (Thing []) new Object [sz]; , pourquoi ne pouvez-vous pas simplement faire array = new Thing [sz]; ?


@AshishkumarSingh Je peux ... mais pourquoi?


Est-ce que cela répond à votre question? Comment créer un tableau générique en Java?


@Priyam, je ne crois pas. Cette question semble demander de créer un tableau de type T , pas un tableau de type SomeClass .


@CarlaCvekla Votre tentative de conversion est l'équivalent de "Ce tableau d'objets est en fait un tableau de choses", auquel la JVM dit alors "non ce n'est pas" et lance une ClassCastException . Vous utiliseriez donc new Thing [sz] parce que c'est correct.


@Kayaman pourquoi la JVM ne se plaint-elle pas du premier cas "Ce tableau d'objets est en fait un tableau de T", mais le fait-il pour un tableau de Thing ?


@CarlaCvekla Qu'en est-il de la réponse que j'ai mentionnée ci-dessous avec Array.newInstance? Si cela ne résout pas non plus votre problème, pouvez-vous expliquer pourquoi?


@CarlaCvekla parce que grâce à l'effacement de type T est en fait Object , donc la JVM le voit pendant l'exécution comme (Object []) new Object [sz]; et il ne peut jamais échouer. La raison de ce type de comportement est historique et ce n'est probablement pas quelque chose dont vous devez vous inquiéter pour vos devoirs. Dans le travail régulier, vous ne rencontrez pas cela trop souvent, car vous travaillez généralement avec des collections au lieu de tableaux de toute façon.


@Priyam la solution donnée dans le commentaire d'Ashishkumar semble fonctionner, je n'ai pas accepté de réponse car je ne sais pas quelle réponse est la meilleure.


@Priyam Je suis celui qui a voté pour. Si vous pouvez justifier votre utilisation d'un constructeur de tableau dynamique dans votre réponse, je vous donnerai également un vote favorable.


@Kayaman Je n'étais pas sûr à l'origine si OP avait accepté la réponse pour aller avec le nouvel opérateur comme mentionné dans le commentaire de suivi, donc j'ai donné une solution alternative. Il semble maintenant que le PO ait finalement utilisé la réponse d'Ashish. Quoi qu'il en soit, je garderai ma réponse là-bas comme alternative. J'ai moi aussi voté pour la réponse d'Ashish car c'est une meilleure solution que la mienne.


3 Réponses :


0
votes

Essayez ceci:

public class Thing<T> {
}

class Test<T> {
    private Thing<T>[] array;

    @SuppressWarnings("unchecked")
    public Test(int sz) {
        array = (Thing[]) Array.newInstance(Thing.class, sz);
    }

    public static void main(String[] args) {
        Test<Object> test = new Test<>(1);
    }
}

Vous pouvez en outre consulter ici


0 commentaires

2
votes

Vous essayez de convertir une liste d ' Object en Thing ce qu'un Object n'est pas, donc cela ne fonctionnera pas.

Le problème auquel vous êtes confronté est que en Java vous ne peut pas instancier un tableau de types génériques .

Créez donc plutôt un tableau de type brut Thing [] et convertissez-le en type générique Thing [] , ce qui est OK dans ce cas étant donné qu'il n'y a l'effacement de type se produit quand même.

class Thing<T> {
}

class Test<T> {
    private Thing<T>[] array;

    @SuppressWarnings("unchecked")
    public Test(int sz) {
        array = (Thing<T>[]) new Thing[sz];
    }

    public static void main(String[] args) {
        Test<Object> test = new Test<>(1);
    }
}


2 commentaires

Y a-t-il une raison de convertir la nouvelle chose [sz] en chose [] ? Cela semble fonctionner même sans le casting.


@CarlaCvekla, non, c'est essentiellement la même chose. Dans un cas, il s'agit d'une distribution non contrôlée et dans l'autre, il s'agit d'une affectation non contrôlée.



0
votes

Lorsque vous castez Object [] en T [] , c'est un mensonge car il est incorrect si T est autre chose que < code> Objet . Cependant, cela ne provoque pas d'exception de conversion de classe à l'intérieur de la classe car l'intérieur de la classe est dans la portée de la variable de type T , donc le type de la variable array , T [] , est effacé en Object [] au moment de l'exécution, donc le cast de Object [] vers celui-ci n'échoue pas (mais exposer le tableau à l'extérieur de la classe en tant que type T [] , l'appelant extérieur peut obtenir une exception de conversion de classe).

Si T avait une limite supérieure comme , alors l'effacement de T [] serait MyClass [] , donc le cast de Object [] vers celui-ci lèverait immédiatement une exception de cast de classe, et vous devriez faire new MyClass [sz] pour qu'il pas immédiatement lancer une exception de conversion de classe.

Ici, la variable est de type Thing [] , dont l'effacement est Thing [] . Vous devrez donc créer un tableau avec new Thing [sz] pour qu'il ne lance pas d'exception de conversion de classe.


0 commentaires