8
votes

Y a-t-il une version générique de Array.Newinstance?

J'ai remarqué que dans Java Array.Newinstance () Code> retour objet code>, plutôt que t [] code>. Il est compréhensible car cette méthode a été introduite avant que Java prend en charge les types génériques.

Cependant, il est surprenant qu'il n'y a pas de version générique équivalente de cela. Java 7's arranges.copyof code> n'est pas identique - il copie le contenu du paramètre plutôt que de créer une nouvelle matrice factice (avec tous les objets NULL à l'intérieur). P>

Depuis la mise en œuvre de Cela semble trivial, y a-t-il une raison de ne pas l'ajouter dans la JRE? ou je ne peux tout simplement pas en trouver un? p>

update strong> p>

Il semble que je fournisse ma propre implémentation "triviale" pour arrêter le malentendu de la question. P >

class MyArrayUtil {
    //Generic version for classes
    @SuppressWarnings("unchecked")
    public static <T> T[] newArrayOf(T[] t, int len){
        return (T[]) Array.newInstance(t.getClass().getComponentType(), len);
    }
    //For array of int
    public static int[] newArrayOf(int[] t, int len){
        return new int[len];
    }
    //For other primitive types...
}


13 commentaires

Non, il est impossible de mettre en œuvre cela dans une mode de sécurité de type compacuation. Par exemple, vous ne pouvez pas créer une nouvelle instance d'une liste: [] . Le compilateur ne saura jamais ce que le type de t est, et il ne peut donc pas garantir que le code client est sûr.


Depuis Arrays.Copyof peut faire le travail Il n'y a aucune raison évidente que vous ne pouvez pas.


Arrays.copyof détermine le type de béton de la matrice à copier.


Donc, cela va bien d'avoir un similaire.newinstanceof qui utilise un type concret pour fournir des informations de type, et comme ce que j'ai dit dans la question, cette mise en œuvre est triviale.


Sorte d'un poulet dans le problème de l'œuf avec votre méthode. Afin de créer un tableau, je dois déjà avoir déjà instancié un tableau du type donné. À ce moment-là, je ne peux que Nouveau moi-même. Votre méthode n'offre aucun avantage sur l'existant.


Essayez: T [] NewInstance (Classe Clazz, Int Longueur) Je suis sur mon téléphone, je ne peux pas tester. Jetez un coup d'œil à angelikalanger.com/genericsfaq/javagenericsfaq.html Aussi


@Kyle Vous avez raison si j'ai une méthode comme la vôtre, cela peut être plus utile. Cependant, cela ne signifie pas que la mienne n'a aucun moyen d'utiliser. Supposons simplement que vous souhaitiez simplement écrire un code générique qui réorganise (doubler le côté, la souffrant, etc.) un tableau existant.


FWIW, GUAVA fournit Juste une telle méthode .


@yshavit Vous obtenez le plus proche de la réponse ... Pouvez-vous continuer et poster votre réponse? Quoi qu'il en soit, les tableaux de Guava semble ne pas prendre en charge les types primitifs.


@yshavit a également trouvé la réponse que vous venez de supprimer a du sens sur le raisonnement. Pouvez-vous la restaurer et ajouter la référence GUAVA et en discuter? Cela semble être une réponse acceptable.


@Arthengine juste fait, merci. :)


Pourquoi pas simplement utiliser arrayes.copyofrange (t, t.length, t.length + len) ?


@Jules car il exige que vous ayez une instance existante en main, mais NewInstance n'exige rien.


3 Réponses :


4
votes

Non, vous devez transmettre le type de béton comme un paramètre d'une manière ou d'une autre. Comme vous l'avez mentionné, arranges.copyof code> montre ceci en action.

Class<T> type = determinteTheTypeSomehow();
return (T[]) Array.newInstance(type, length);


3 commentaires

array.newinstance nécessite une classe <> , comme arrangé.copyof nécessite t [] , alors ils le font nécessite un paramètre supplémentaire plutôt qu'un paramètre de type. Je me demande simplement pourquoi nous ne pouvons pas avoir de arranges.newinstance qui accepte class ou t [] (en tant que modèle uniquement; contenu à l'intérieur est ignoré).


Oui, je comprends, mais vous essayez de plier l'API à vos besoins qui ne fonctionneront jamais;) J'admise que cela peut être frustrant cependant c'est comme ça.


Lorsque j'écris des types de génériques, je passe souvent dans le type de paramètre concret comme un argument du constructeur pour ces objectifs (et autres).



8
votes

GUAVA fournit Une telle fonction . Ce n'est pas la première fois que Guava (ou Apache Commons) a fourni une aide couramment utilisée que le JDK n'a pas, pour une raison quelconque.

Vous pouvez le savoir, mais certains de fond pour le googler qui trébuchent sur cela à l'avenir. : La raison pour laquelle la signature ne peut pas être rendue générique est que la méthode array.newinstance Retour Objet dans Java 1.4 , Donc, pour la compatibilité en arrière, la version brute de la méthode doit également renvoyer objet . S'il avait été génendu comme: xxx

... alors le type de retour serait objet [] , pas objet . Cela briserait la compatibilité à l'envers, que les concepteurs Java ont toujours essayé très fort de ne pas le faire.

the des tableaux.Copyof est entré uniquement avec Java 1.6, et donc n'a donc pas se soucier de la compatibilité en arrière.


5 commentaires

Maintenant, je pense que je comprends bien pourquoi il n'a pas beaucoup de sens d'avoir Newarray prend en charge les types primitifs. Si vous souhaitez créer un nouveau tableau avec des types qui ne sont pas un paramètre de type générique, vous pouvez simplement utiliser nouveau xyz [] . Si ce n'est pas le cas, vous devez utiliser le type de classe et que dans ce cas, le Newarray est utile.


Cela ne devrait pas être un problème si vous avez besoin d'un paramètre / champ similaire dans votre méthode Signature / Classe Définition.


@Arthengine En outre, il fonctionne pour des types primitifs, car int.class existe (et de même pour les autres primitives). Voir Ideone.com/ATVBJX pour un exemple.


Je sais que c'est possible. Mais cela n'a aucun sens si vous avez une classe classe d'instance à l'exécution. Et dans ce cas, votre code utilise explicitement la réflexion, pas seulement générique.


Étant donné que la modification du type de retour effacé de objet à objet [] est un rétrécissement, il devrait au moins en théorie être compatible Binaire.



3
votes

la raison de base que array.newinstance () ne peut pas être déclaré comme t [] NewInstance (classe classe, intorme) est parce qu'il peut être utilisé pour créer des tableaux de primitives. Donc, par exemple, si vous passez dans int.class , qui a le type classe , puis à partir de la déclaration que vous vous attendriez à renvoyer un integer [ ] objet. Cependant, la fonction renvoie réellement un objet int [] , qui n'est pas un sous-type de entier [] , il a donc le mauvais type.

sûr, ils auraient pu ajouter une méthode supplémentaire comme NewreFerenceArrayInstance () qui interdit les types primitifs (par exemple, jette une exception lorsqu'il est passé un type primitif) et peut donc être déclaré en toute sécurité Pour retourner t [] . Cependant, cela semble être ajouté une méthode complètement redondante uniquement pour éviter une coulée non cochée.


0 commentaires