Pourquoi BigInteger n’est-il pas une primitive?

Si vous utilisez BigInteger (ou BigDecimal ) et souhaitez effectuer un calcul arithmétique, vous devez utiliser les méthodes add ou subtract , par exemple. Cela peut sembler correct jusqu’à ce que vous réalisiez que

  i += d + p + y; 

serait écrit comme ceci pour un BigInteger :

  i = i.add(d.add(p.add(y))); 

Comme vous pouvez le constater, il est un peu plus facile de lire la première ligne. Ce problème pourrait être résolu si Java autorisait la surcharge d’opérateurs mais ce n’est pas le cas, ce qui soulève la question suivante:

Pourquoi BigInteger n’est-il pas un type primitif pour pouvoir tirer parti des mêmes opérateurs que les autres types primitifs?

En effet, BigInteger n’est en réalité rien d’ BigInteger primitif. Il est mis en œuvre à l’aide d’un tableau et de certains champs supplémentaires. Les différentes opérations incluent des opérations complexes. Par exemple, voici l’implémentation de add :

 public BigInteger add(BigInteger val) { if (val.signum == 0) return this; if (signum == 0) return val; if (val.signum == signum) return new BigInteger(add(mag, val.mag), signum); int cmp = compareMagnitude(val); if (cmp == 0) return ZERO; int[] resultMag = (cmp > 0 ? subtract(mag, val.mag) : subtract(val.mag, mag)); resultMag = trustedSsortingpLeadingZeroInts(resultMag); return new BigInteger(resultMag, cmp == signum ? 1 : -1); } 

Les primitives en Java sont des types qui sont généralement implémentés directement par le processeur de la machine hôte. Par exemple, chaque ordinateur moderne dispose d’une instruction en langage machine pour l’addition d’entiers. Par conséquent, il peut également avoir un code octet très simple dans la JVM.

Un type complexe tel que BigInteger ne peut généralement pas être traité de cette manière et ne peut pas être traduit en simple code octet. Ce ne peut pas être un primitif.


Votre question pourrait donc être “Pourquoi aucune surcharge d’opérateur en Java”. Cela fait partie de la philosophie linguistique.


Et pourquoi ne pas faire une exception, comme pour Ssortingng ? Car ce n’est pas un seul opérateur qui fait exception. Vous devez créer une exception pour les opérateurs * , / , + , - , << , ^ et ainsi de suite. Et vous aurez toujours quelques opérations dans l'object lui-même (comme pow qui n'est pas représenté par un opérateur en Java), qui pour les primitives sont traitées par des classes spécialisées (comme Math ).

Fondamentalement, parce que le mot “primitif” signifie “primitif”, il s’agit de données pouvant être traitées directement avec une seule instruction de processeur . En d’autres termes, ce sont des primitives car elles tiennent dans un mot de 32 ou 64 bits, qui correspond à l’architecture de données avec laquelle votre CPU travaille, afin qu’elles puissent être explicitement stockées dans les registres .

Et ainsi votre CPU peut effectuer l’opération suivante:

 ADD REGISTER_3 REGISTER_2 REGISTER_1 ;;; REGISTER_3 = REGISTER_1 + REGISTER_2 

Un BigInteger qui peut occuper une quantité de mémoire arbitrairement grande ne peut pas être stocké dans un seul ENREGISTREMENT et devra exécuter plusieurs instructions pour effectuer une simple sum.

C’est pourquoi ils ne pourraient pas être un type primitif, et ce sont maintenant des objects avec des méthodes et des champs, une structure beaucoup plus complexe que les simples types primitifs.

Remarque: la raison pour laquelle j’ai appelé cet informel est que, finalement, les concepteurs Java pourraient définir un “type primitif Java” comme tout ce qu’ils voulaient, ils possèdent le mot, mais c’est vaguement l’utilisation convenue du mot.

int et boolean et char ne sont pas des primitives afin que vous puissiez tirer parti des opérateurs tels que + et / . Ce sont des primitives pour des raisons historiques, dont la plus importante est la performance.

En Java, les primitives sont définies uniquement comme des éléments qui ne sont pas des objects à part entière. Pourquoi créer ces structures inhabituelles (et les ré-implémenter ensuite comme des objects propres, comme Integer , plus tard)? Principalement pour la performance: les opérations sur les objects étaient (et sont) plus lentes que les opérations sur les types primitifs. (Comme d’autres réponses le mentionnent, le support matériel a rendu ces opérations plus rapides, mais je ne suis pas du même avis, ce support est une “propriété essentielle” des primitives.)

Ainsi, certains types ont reçu un “traitement spécial” (et ont été implémentés en tant que primitifs), d’autres non. Pensez-y ainsi: si même le très populaire Ssortingng n’est pas un type primitif, pourquoi BigInteger serait-il?

C’est parce que les types primitifs ont une taille limite. Par exemple, int correspond à 32 bits et long à 64 bits. Donc, si vous créez une variable de type int, la machine virtuelle alloue 32 bits de mémoire sur la stack. Mais comme pour BigInteger, il n’est “théoriquement” pas limité en taille. Ce qui signifie qu’il peut grossir de manière arbitraire. De ce fait, il n’ya aucun moyen de connaître sa taille et d’allouer un bloc de mémoire fixe sur la stack. Par conséquent, il est alloué sur le segment de mémoire où la JVM peut toujours augmenter la taille si nécessaire.

Les types primitifs sont normalement des types historiques définis par l’architecture du processeur. C’est pourquoi l’octet est de 8 bits, short de 16 bits, int de 32 bits et long de 64 bits. Peut-être que lorsqu’il y aura plus d’architectures 128 bits, une primitive supplémentaire sera créée … mais je ne vois pas suffisamment de lecteur pour cela …