Pourquoi L'API Java utilise-t-elle int au lieu de short ou byte?

pourquoi L'API Java utilise-t-elle int , alors que short ou même byte serait suffisant?

exemple: le champ DAY_OF_WEEK de la classe Calendar utilise int .

si la différence est trop minime, alors pourquoi ces types de données ( short , int ) existent-ils?

130
demandé sur shmosel 2014-11-25 12:11:41

6 réponses

certaines des raisons ont déjà été soulignées. Par exemple, le fait que "...(Presque) toutes les opérations sur byte, short fera la promotion de ces primitives à int" . Cependant, la question suivante évidente serait: pourquoi ces types sont-ils promus à int ?

donc pour aller un niveau plus profond: la réponse peut simplement être liée à L'ensemble D'Instruction Java Virtual Machine. Comme le résume dans le tableau de la spécification de la machine virtuelle Java , tous opérations arithmétiques intégrales, comme l'ajout, la division et d'autres, ne sont disponibles que pour le type int et le type long , et pas pour les plus petits types.

(aparté: Les plus petits types ( byte et short ) sont essentiellement destinés seulement pour "1519200920 des" tableaux . Un array comme new byte[1000] va prendre 1000 octets, et un tableau comme new int[1000] prendra 4000 octets)

Maintenant, bien sûr, on pourrait dire que "...la question suivante évidente serait: pourquoi ces instructions sont-elles seulement offertes pour int (et long )?" .

une raison est mentionnée dans les spécifications de la JVM mentionnées ci-dessus:

si chaque instruction dactylographiée supportait tous les types de données d'exécution de la machine virtuelle Java, il y aurait plus d'instructions que ce qui pourrait être représenté dans un octet

de plus, la machine virtuelle Java peut être considérée comme une abstraction d'un vrai processeur. Et l'introduction de unité logique arithmétique dédiée aux petits types ne serait pas la peine de l'effort: il aurait besoin de transistors supplémentaires, mais il pourrait encore n'exécute qu'une addition par cycle d'horloge. L'architecture dominante lorsque le JVM a été conçu était de 32 bits, juste à droite pour un int de 32 bits . (Les opérations qui impliquent une valeur 64bit long sont mises en œuvre comme un cas spécial).

(Note: le dernier paragraphe est un peu simplifié, compte tenu d'une vectorisation possible, etc., mais devrait donner l'idée de base sans plonger trop profondément dans les sujets de conception de processeur)


éditer: un petit addendum, mettant l'accent sur l'exemple de la question, mais dans un sens plus général: on pourrait également se demander s'il ne serait pas bénéfique de stocker champs en utilisant les plus petits types. Par exemple, on pourrait penser que la mémoire pourrait être sauvée en stockant Calendar.DAY_OF_WEEK comme un byte . Mais ici, le Format de fichier de classe Java entre en jeu: tous les champs dans un fichier de classe occupent au moins un "logement", qui a la taille d'un int (32 bits). (Le "large", double et long , occupent deux emplacements). Ainsi, déclarer explicitement un champ comme short ou byte n'enregistrerait pas non plus de mémoire.

160
répondu Marco13 2017-05-23 12:34:45

(presque) toutes les opérations sur byte , short vont les promouvoir à int , par exemple, vous ne pouvez pas écrire:

short x = 1;
short y = 2;

short z = x + y; //error

arithmétique plus facile et simple en utilisant int , pas besoin de mouler.

en termes d'espace, il fait un très peu de différence. byte et short compliqueraient les choses, je ne pense pas que cette micro optimisation en vaut la peine puisque nous sommes parler d'un nombre fixe de variables.

byte est pertinent et utile lorsque vous programmez pour des périphériques embarqués ou traitant de fichiers/réseaux. En outre, ces primitives sont limitées, et si les calculs pourraient dépasser leurs limites à l'avenir? Essayez de penser à une extension de la classe Calendar qui pourrait faire apparaître de plus grands nombres.

notez aussi que dans un processeur 64 bits, les locaux seront sauvegardés dans des registres et n'utiliseront aucun utiliser int , short et d'autres primitives ne fera aucune différence. De plus, de nombreuses implémentations Java alignent les variables * (et les objets).


* byte et short occupent le même espace que int s'ils sont variables locales , classe variables ou même instance variables. Pourquoi? Parce que dans (la plupart) les systèmes informatiques, les adresses des variables sont aligné , donc par exemple si vous utilisez un seul octet, vous finirez en fait avec deux octets - un pour la variable elle-même et un autre pour le remplissage.

d'autre part, dans les tableaux, byte prendre 1 byte, short prendre 2 octets et int prendre quatre octets, parce que dans les tableaux seulement le début et peut-être la fin de celui-ci doit être aligné. Ce fera une différence dans le cas où vous voulez utiliser, par exemple, System.arraycopy() , alors vous noterez vraiment une différence de performance.

37
répondu Maroun 2015-04-28 07:56:35

parce que les opérations arithmétiques sont plus faciles quand on utilise des entiers par rapport aux shorts. Supposons que les constantes ont été effectivement modélisées par des valeurs short . Vous devez alors utiliser L'API de cette manière:

short month = Calendar.JUNE;
month = month + (short) 1; // is july

Notez le casting explicite. Les valeurs courtes sont implicitement promues aux valeurs int lorsqu'elles sont utilisées dans des opérations arithmétiques. (Sur la pile de l'opérande, les shorts sont même exprimés en ints.) Cela serait assez lourd à utiliser qui c'est pourquoi les valeurs int sont souvent préférées pour les constantes.

par rapport à cela, le gain en efficacité de stockage est minime parce qu'il n'existe qu'un nombre fixe de telles constantes. Nous parlons de 40 constantes. Changer leur rangement de int à short vous protégerait 40 * 16 bit = 80 byte . Voir cette réponse pour plus de détails.

7
répondu Rafael Winterhalter 2017-05-23 12:26:38

si vous avez utilisé la philosophie où les constantes intégrales sont stockées dans le plus petit type qu'elles rentrent, alors Java aurait un problème sérieux: chaque fois que les programmeurs écrivent du code en utilisant des constantes intégrales, ils doivent faire attention à leur code pour vérifier si le type des constantes importe, et si oui, regardez le type dans la documentation et/ou faites toutes les conversions de type sont nécessaires.

donc maintenant que nous avons souligné un problème sérieux, Quels avantages pourrait vous espérez atteindre avec cette philosophie? Je ne serais pas surpris si le seulement effet d'exécution-observable de ce changement serait ce type que vous obtenez lorsque vous regardez la constante vers le haut via la réflexion. (et, bien sûr, quelles que soient les erreurs introduites par les programmeurs paresseux/involontaires ne tenant pas compte correctement des types de constantes)

peser le pour et le contre est très facile: c'est une mauvaise philosophie.

5
répondu Hurkyl 2014-11-28 02:58:10

la complexité de la conception d'une machine virtuelle est fonction du nombre d'opérations qu'elle peut effectuer. Il est plus facile d'avoir quatre implémentations d'une instruction comme "multiplier"--une pour chaque entier de 32 bits, 64-bit entier, 32-bit flottant-point, et 64-bit flottant-point--que d'avoir, en plus des versions ci-dessus, pour les petits types numériques aussi bien. Une question de conception plus intéressante est pourquoi il devrait y avoir quatre types, plutôt que moins (effectuer tous les entiers les calculs avec des entiers de 64 bits et / ou faisant tous les calculs à virgule flottante avec des valeurs à virgule flottante de 64 bits). La raison pour utiliser des entiers 32 bits est que Java devait fonctionner sur de nombreuses plates-formes où les types 32 bits pouvaient être utilisés aussi rapidement que les types 16 bits ou 8 bits, mais les opérations sur les types 64 bits seraient sensiblement plus lentes. Même sur les plateformes où les types 16 bits seraient plus rapides à travailler, le coût supplémentaire de travailler avec des quantités 32 bits serait compensé par la simplicité permis par seulement ayant des types 32 bits.

quant à l'exécution de calculs à virgule flottante sur des valeurs de 32 bits, les avantages sont un peu moins clairs. Il existe des plates-formes où un calcul comme float a=b+c+d; pourrait être effectué le plus rapidement en convertissant tous les opérandes à un type de plus grande précision, en les ajoutant, puis en convertissant le résultat de nouveau à un nombre flottant de 32 bits pour le stockage. Il y a d'autres plateformes où il serait plus efficace pour effectuer tous les calculs à l'aide de valeurs à virgule flottante 32 bits. Les créateurs de Java ont décidé que toutes les plates-formes devraient être tenues de faire les choses de la même manière, et qu'ils devraient favoriser les plates-formes matérielles pour lesquelles 32 bits de calcul à virgule flottante sont plus rapides que les plus longues, même si cela gravement dégradé PC à la fois la vitesse et la précision des mathématiques à virgule flottante sur un PC typique, ainsi que sur de nombreuses machines sans unités à virgule flottante. Remarque, d'ailleurs, que selon le les valeurs de b, c, et d, en utilisant des calculs intermédiaires de plus grande précision lorsque l'on calcule des expressions comme float a=b+c+d; ci-dessus, donnent parfois des résultats qui sont beaucoup plus précis que ceux qui seraient obtenus de tous les opérandes intermédiaires ont été calculés à la précision float , mais donnent parfois une valeur qui est un tout petit peu moins précise. Dans tous les cas, Sun a décidé que tout devait être fait de la même manière, et ils ont opté pour l'utilisation des valeurs de précision minimale float .

notez que les principaux avantages des types de données plus petits deviennent apparents lorsque de grands nombres d'entre eux sont stockés ensemble dans un tableau; même s'il n'y avait aucun avantage à avoir des variables individuelles de types plus petits que 64 bits, il est intéressant d'avoir des tableaux qui peuvent stocker des valeurs plus petites plus compactly; ayant une variable locale être un byte plutôt que d'un long sauve sept octets; ayant un tableau de 1.000.000 nombres tiennent chaque nombre comme un byte plutôt qu'un long vagues de 7,000,000 octets. Puisque chaque type de tableau n'a besoin que de supporter quelques opérations (notamment lire un élément, stocker un élément, Copier une gamme d'éléments dans un tableau, ou copier une gamme d'éléments d'un tableau à un autre), la complexité ajoutée d'avoir plus de types de tableau n'est pas aussi sévère que la complexité d'avoir plus de types de valeurs numériques discrètes directement utilisables.

4
répondu supercat 2014-11-25 19:25:03

en fait, il y aurait un petit avantage. Si vous avez un

class MyTimeAndDayOfWeek {
    byte dayOfWeek;
    byte hour;
    byte minute;
    byte second;
}

puis sur une JVM typique il a besoin d'autant d'espace qu'une classe contenant un seul int . La consommation de mémoire est arrondie à un prochain multiple de 8 ou 16 octets (IIRC, c'est configurable), donc les cas où il y a une réelle économie sont plutôt rares.

cette classe serait légèrement plus facile à utiliser si les méthodes correspondantes Calendar étaient retournées a byte . Mais il n'y a pas de telles méthodes Calendar , seulement get(int) qui doivent retourner un int en raison d'autres champs. Chaque opération sur des types plus petits favorise à int , donc vous avez besoin de beaucoup de casting.

très probablement, vous allez soit abandonner et passer à un int ou écrire des setters comme

void setDayOfWeek(int dayOfWeek) {
    this.dayOfWeek = checkedCastToByte(dayOfWeek);
}

alors le type de DAY_OF_WEEK n'a pas d'importance, de toute façon.

2
répondu maaartinus 2014-11-28 12:12:26