Ne comprends pas le code source de Arrays.copyOf

J’ai du mal à comprendre le code source de Arrays.copyOf .

 public static  T[] copyOf(U[] original, int newLength, Class newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 
  1. quel est ce contrôle de ligne?

     (Object)newType == (Object)Object[].class 
  2. Quelles sont les différences entre (T[]) new Object[newLength] et (T[]) Array.newInstance(newType.getComponentType(), newLength) . pourquoi Array.newInstance pas assez bon pour les deux cas?

  3. Cette ligne suivante comstack, mais se bloque au moment de l’exécution (comme prévu). Quand devrais-je utiliser cette méthode?

     Integer[] nums = Arrays.copyOf(new Ssortingng[]{"a", "b"}, 2, Integer[].class) 

Quelle est cette ligne de vérification? (Object)newType == (Object)Object[].class

C’est vérifier l’égalité simple (probablement dans le but d’une micro-optimisation, mais plus tard).

Le casting inhabituel est nécessaire car Class (le type de Object[].class ) et Class Class sont des types incomparables. Fondamentalement, pour qu’une comparaison d’égalité avec == comstack, l’un des côtés doit être un sous-type ou un supertype de l’autre.

Ie nous ne pouvons pas faire:

 // doesn't comstack // this expression can never evaluate to true (new Integer(0) == new Float(0f)) 

Les règles pour les types génériques sont un peu plus compliquées et il y a quelques cas où une comparaison ne comstack pas, mais elle peut quand même être évaluée comme vraie.

La raison pour laquelle la Class n’est pas un sur- Class de Class Class , bien Object[] soit un supertype de tous les types de tableau d’objects, est que les génériques Java sont invariants sans la présence d’un caractère générique.

Une autre façon de faire la comparaison serait:

 (newType == (Class)Object[].class) 

Quelles sont les différences entre (T[]) new Object[newLength] et (T[]) Array.newInstance(newType.getComponentType(), newLength) ?

  • new Object[...] crée un tableau de manière normale, d’un type connu statiquement. Rappelez-vous que le code vient de vérifier que T[] est Object[] .
  • Array.newInstance(...) utilise la reflection pour créer dynamicment un tableau du type de Class transmis.

Pourquoi Array.newInstance pas assez bon pour les deux cas?

Une opération utilisant la reflection est généralement plus lente que son homologue non réfléchissant.

Le tutoriel de reflection dit:

Étant donné que la reflection implique des types résolus dynamicment, certaines optimisations de la machine virtuelle Java ne peuvent pas être effectuées. Par conséquent, les opérations de reflection ont des performances plus lentes que leurs homologues non réfléchissantes et doivent être évitées dans les sections de code appelées fréquemment dans les applications sensibles aux performances.

Java SE est rempli de micro-optimisation comme celle-ci. Les rédacteurs de SE essaient de tout faire pour en sortir.

Mais je ne m’inquiéterais pas d’un newInstance performance dans ce cas: newInstance et copyOf sont des éléments insortingnsèques de HotSpot . Cela signifie que, idéalement, les appels à ces méthodes sont remplacés par un assemblage spécifique à la machine. De façon anecdotique, j’ai effectué des tests et constaté que la différence entre les new Object[...] et Array.newInstance(...) était négligeable. Le code dans la question est probablement une relique, bien que cela puisse encore être utile sur les JVM moins bien équipées.

La reflection peut également être désactivée dans certains contextes avec une sécurité ssortingcte (telle qu’une applet), mais pas généralement pour une application de bureau normale.

Quand devrais-je utiliser cette méthode?

En général, vous n’utiliserez probablement jamais cette surcharge. Cette surcharge n’est utile que si vous souhaitez modifier le type du tableau.

  • Élargissement:

     Object[] a = Arrays.copyOf( new Ssortingng[] { "hello", "world" }, 3, Object[].class); a[2] = Character.valueOf('!'); System.out.println(Arrays.toSsortingng(a)); 
  • Rétrécissement:

     Ssortingng[] a = Arrays.copyOf( new Object[] { "hello", "world" }, 2, Ssortingng[].class); System.out.println(Ssortingng.join(" ", a)); 

Il est plus Arrays.copyOf(T[], int) utiliser Arrays.copyOf(T[], int) .

  1. quel est ce contrôle de ligne?
 (Object)newType == (Object)Object[].class 

Il vérifie si la variable newType contient une référence à une instance de java.lang.Class représentant le type Object[] . Les moulages sont inutiles.

  1. Quelles sont les différences entre (T[]) new Object[newLength] et (T[]) Array.newInstance(newType.getComponentType(), newLength) . pourquoi Array.newInstance pas assez bon pour les deux cas?

Autant que je Array.newInstance() , Array.newInstance() pourrait être utilisé dans les deux cas, mais la construction de tableaux ordinaires non réfléchissants est probablement un peu plus rapide. Ainsi, je suppose que Object[] est appelé comme un cas particulier pour des raisons de performances, mais je ne sais pas si ce cas est suffisamment utilisé pour que l’optimisation soit importante.

  1. Cette ligne suivante comstack, mais se bloque au moment de l’exécution (comme prévu). Quand devrais-je utiliser cette méthode?
 Integer[] nums = Arrays.copyOf(new Ssortingng[]{"a", "b"}, 2, Integer[].class) 

Vous devez l’utiliser lorsque vous devez copier un tableau dans un tableau avec un type d’élément éventuellement différent (mais compatible), en particulier lorsque les types d’éléments ne sont pas connus statiquement. Si vous voulez que la copie ait le même type d’élément que l’original, il est alors plus facile d’utiliser la méthode clone() du tableau d’origine.

  1. Il vérifie si newType est un tableau d’objects ou non:

     Object[] a1 = new Object[100]; -- array of Objects Ssortingng[] a2 = new Ssortingng[100]; -- array of Ssortingngs 

Pourquoi faire ça? Parce que new Object [n] est plus rapide que Array.newInstance

  1. Array.newInstance(Class componentType, int... dimensions) crée un tableau de types défini par le premier argument, par exemple Ssortingng.class -> Ssortingng[] . Notez que Ssortingng[].class.getComponentType() renvoie Ssortingng.class

  2. Vous ne pouvez pas l’utiliser comme ça, mais ça peut être comme ça

     Integer[] nums = Arrays.copyOf(new Object[]{1, 2}, 2, Integer[].class); 

dans ce cas, cela ne dépend que du type d’éléments, par exemple

  Arrays.copyOf(new Object[]{1L, 2}, 2, Integer[].class); 

va échouer, vous ne pouvez pas écrire dans Integer[] autre que Integer

Tout d’abord, le casting dans cette ligne

 ((Object)newType == (Object)Object[].class) 

sont absolument nécessaires. Leur suppression entraînera une erreur de compilation:

 incomparable types: Class and Class where CAP#1 is a fresh type-variable: CAP#1 extends T[] from capture of ? extends T[] 

Maintenant, pour répondre à votre question Qu’est-ce que cette vérification de ligne?

Il vérifie simplement si le tableau donné est de type object, ce qui fait partie de la réponse à votre autre question Pourquoi Array.newInstance pas assez bonne pour les deux cas?

Dans le premier cas, nous soaps déjà que le tableau est de type Object , il est donc inutile d’appeler la méthode newInstance pour récupérer le type correct, cela entraînerait uniquement une perte de performances.

Comme pour votre dernier exemple,

 Integer[] nums = Arrays.copyOf(new Ssortingng[]{"a", "b"}, 2, Integer[].class) 

Cela comstack, c’est vrai. Parce que les arguments donnés à la méthode sont tous valides. Il échouera certainement à l’exécution; quelle serait la sortie attendue de la conversion de “a” en type Integer ?

Maintenant, quand utiliser copyOf ? Lorsque vous connaissez déjà les deux types et que vous savez déjà qu’ils sont valables ensemble.

Son utilisation principale est de renvoyer une copie mais tronquée ou complétée avec [valeurs null / default] dans le tableau d’origine.

Laissez-moi tenter de répondre à ceci:

Pour répondre à votre première question, il vérifie si le type newType est identique aux types du tableau. Les deux sont également en train de mettre à niveau les types vers un type d’object. En d’autres termes, il essaie de voir si le type parent du tableau est object. Voir cette question de SO sur Upcasting et Downcasting . Je suppose que ce n’est pas parce que pour vérifier la sécurité de type. Même si tous les objects de Java dérivent d’objects comme une super-classe.

Il serait utile de noter que

  T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); 

est en fait une ligne. c’est à dire que c’est en fait un conditionnel if-else.

result = (condition) ? (doThisIfTrue) : (elseDoThisIfFalse)

Exemple simple ici

Donc, essentiellement, cette ligne serait la même que:

 T[] copy; Boolean condition = ((Object)newType == (Object)Object[].class) if(condition) copy = (T[]) new Object[newLength]; else copy = (T[]) Array.newInstance(newType.getComponentType(), newLength); 

La raison pour laquelle la création d’une nouvelle instance dans Array.newInstance est probablement un choix de performance, où si le programme doit toujours créer de nouvelles instances, cela coûtera plus cher que d’initialiser directement un tableau d’objects génériques et de copier les choses.

Arrays.copyOf créera un nouveau tableau (avec des références à l’ancien) mais avec une longueur plus récente et remplira les positions inutilisées avec des objects vides. C’est ce qu’il fait sur un tableau d’ints dans lequel il tamponne les index inutilisés avec des zéros.

Arrays.CopyOf sert à fournir une copie superficielle des objects, c’est-à-dire qu’il fait référence aux anciens éléments, mais dans un nouveau tableau . Cette question SO a plus d’informations à ce sujet.