Pourquoi Java ne supporte-t-il pas les ints non signés?

pourquoi Java ne prend-il pas en charge les entiers non signés?

Il me semble être une omission étrange, étant donné qu'ils permettent d'écrire du code qui est moins susceptible de produire des débordements sur inattendue de la grande entrée.

de plus, l'utilisation d'entiers non signés peut être une forme d'auto-documentation, puisqu'ils indiquent que la valeur que le int non signé était censé contenir n'est jamais supposée être négative.

Enfin, dans certains cas, des entiers non signés peuvent être plus efficaces pour certaines opérations, telles que la division.

Quel est l'inconvénient de les inclure?

345
demandé sur Orkun Ozen 2009-01-10 04:35:33

15 réponses

C'est d'un entretien avec Gosling et d'autres , sur la simplicité:

Gosling: pour moi en tant que concepteur de langue, ce que je ne me considère pas vraiment comme ces jours-ci, ce qui "simple" a vraiment fini par signifier était je pouvais attendre J. Random Developer de tenir la spécification dans sa tête. Cette définition dit que, par exemple, Java n'est pas -- et en fait beaucoup de ces langages finissent avec beaucoup de cas de corner, des choses que personne comprend vraiment. Interrogez n'importe quel développeur C sur non signé, et bientôt vous découvrez que les développeurs presque aucun C comprennent réellement ce qui se passe avec non signé, ce que l'arithmétique non signé est. Des choses comme ça ont rendu c complexe. Le langage Java est, je pense, assez simple. Les bibliothèques que vous devez consulter.

179
répondu Uri 2013-10-06 17:40:21

en lisant entre les lignes, je pense que la logique était quelque chose comme ceci:

  • en général, les concepteurs Java voulaient simplifier le répertoire des types de données disponibles
  • pour des raisons de tous les jours, ils ont estimé que le besoin le plus courant était de types de données signées
  • pour la mise en œuvre de certains algorithmes, l'arithmétique non signée est parfois nécessaire, mais le type de programmeurs qui seraient la mise en œuvre de tels algorithmes aurait également la connaissance de "travailler rond" faire arithmétique non signée avec types de données signé

la plupart du temps, je dirais que c'était une décision raisonnable. Peut-être aurais-je:

  • made octet non signé, ou au moins fournir un signed/unsigned alternatives, éventuellement avec des noms différents, pour ce seul type de données (signé est bon pour des raisons de cohérence, mais quand vous avez besoin d'un octet signé?)
  • supprimé avec "short" (quand avez-vous utilisé pour la dernière fois 16-bit signé arithmétique?)

malgré tout, avec un peu de kludging, les opérations sur des valeurs non signées jusqu'à 32 bits ne sont pas trop mauvaises, et la plupart des gens n'ont pas besoin de division ou de comparaison 64 bits non signée.

50
répondu Neil Coffey 2009-01-10 04:29:03

c'est une question plus ancienne et pat a mentionné brièvement char, j'ai juste pensé que je devrais développer sur ce pour d'autres qui regarderont ce sur la route. Regardons de plus près les types primitifs de Java:

byte de 8 bits entier signé

short - entier signé de 16 bits

int - entier signé 32 bits

long - entier signé de 64 bits

char - caractère à 16 bits (entier non signé)

bien que char ne supporte pas unsigned arithmétique, il peut essentiellement être traité comme un unsigned entier. Vous devriez explicitement mouler les opérations arithmétiques dans char , mais il ne vous fournit un moyen de spécifier unsigned numéros.

char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ? 
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;

Oui, il n'y a pas de support direct pour les entiers non signés (évidemment, je n'aurais pas de reprendre la plupart de mes opérations dans char s'il y avait un soutien direct). Cependant, il existe certainement un type de données primitives non signées. J'aurais aimé voir un octet non signé aussi, mais je suppose que doubler le coût de la mémoire et à la place utiliser char est une option viable.


Modifier

avec JDK8 il y a de nouveaux API pour Long et Integer qui fournissent méthodes d'aide lors du traitement des valeurs long et int comme valeurs non signées.

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

En Plus, Goyave fournit un certain nombre de méthodes d'aide pour faire des choses semblables pour les types entiers qui aide à combler l'écart laissé par le manque de soutien natif pour les entiers unsigned .

18
répondu Jyro117 2015-10-13 10:43:21

Java a des types non signés, ou au moins un: char est un raccourci non signé. Donc quelle que soit L'excuse que Gosling invoque, C'est juste son ignorance qui explique pourquoi il n'y a pas d'autres types non signés.

est aussi de type court: les shorts sont utilisés tout le temps pour le multimédia. La raison est que vous pouvez ajuster 2 échantillons dans un seul 32-bit non signé long et vectoriser de nombreuses opérations. Même chose avec des données 8 bits et un octet non signé. Vous pouvez ajuster 4 ou 8 échantillons dans un registre pour la vectorisation.

16
répondu pat 2009-10-12 07:20:10

dès que les ints signés et non signés sont mélangés dans une expression les choses commencent à devenir confuses et vous probablement will perdre l'information. Le fait de restreindre Java à des produits signés ne fait que clarifier les choses. Je suis content de ne pas avoir à me soucier de toute l'affaire signée/non signée, bien que je manque parfois le 8ème morceau dans un octet.

14
répondu Bombe 2014-08-19 15:24:37

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

ce type dit parce que la norme C définit les opérations impliquant des instruments non signés et signés à être traités comme non signés. Cela pourrait causer des entiers signés négatifs à rouler autour dans un grand int non signé, causant potentiellement des bogues.

12
répondu akatakritos 2009-01-10 01:42:05

je pense que Java est très bien comme il est, ajoutant non signé compliquerait sans beaucoup de gain. Même avec le modèle integer simplifié, la plupart des programmeurs Java ne savent pas comment les types numériques de base se comportent - il suffit de lire le livre Java Puzzlers pour voir quelles idées fausses vous pourriez tenir.

Que des conseils pratiques pour l':

  • si vos valeurs sont quelque peu arbitraires et ne correspondent pas à int , utilisez long . S'ils ne rentrent pas dans long , utilisez BigInteger .

  • utilisez les plus petits types seulement pour les tableaux quand vous avez besoin d'économiser de l'espace.

  • S'il vous faut exactement 64/32/16/8 bits, utilisez long / int / short / byte et arrête de t'inquiéter pour le signe, sauf pour la division, la comparaison, le décalage à droite, et le moulage.

Voir aussi ce répondre au sujet "du portage d'un générateur de nombres aléatoires en C à Java".

11
répondu starblue 2017-08-02 15:31:19

Avec JDK8 il ne avoir un certain soutien pour eux.

nous pouvons encore voir le plein soutien des types non signés en Java malgré les préoccupations de Gosling.

6
répondu John Hascall 2015-10-02 15:13:55

je sais que ce post est trop vieux; cependant pour votre intérêt, en Java 8 et plus tard, vous pouvez utiliser le type de données int pour représenter un entier non signé de 32 bits, qui a une valeur minimale de 0 et une valeur maximale de 2 32 -1. Utilisez la classe Integer pour utiliser le type de données int comme un entier non signé et des méthodes statiques comme compareUnsigned() , divideUnsigned() , etc. ont été ajoutés à la classe Integer à l'appui des opérations arithmétiques pour les entier.

6
répondu Morteza Adi 2017-08-02 15:14:46

j'ai entendu des histoires qu'ils devaient être inclus près de la version Java d'orignal. Oak était le précurseur de Java, et dans certains documents spec il y avait mention de valeurs usignées. Malheureusement, ceux-ci n'ont jamais fait dans le langage Java. Dans la mesure où quelqu'un a pu comprendre qu'ils n'ont tout simplement pas été mis en œuvre, probablement en raison d'une contrainte de temps.

4
répondu Rob Ottaway 2009-01-10 01:45:42

j'ai un jour suivi un cours de C++ avec quelqu'un du Comité des normes C++ qui a laissé entendre que Java avait pris la bonne décision d'éviter D'avoir des entiers non signés parce que (1) la plupart des programmes qui utilisent des entiers non signés peuvent tout aussi bien le faire avec des entiers signés et c'est plus naturel en termes de comment les gens pensent, et (2) en utilisant des entiers non signés résulte en lots faciles à créer mais difficiles à débugger des questions telles que le débordement de l'arithmétique entière et la perte de bits significatifs lors de la conversion entre entiers signés et non signés. Si vous soustrayez par erreur 1 de 0 en utilisant des entiers signés, cela provoque souvent plus rapidement le plantage de votre programme et rend plus facile de trouver le bogue que s'il s'enroule autour de 2^32 - 1, et les compilateurs et les outils d'analyse statique et les vérifications d'exécution doivent supposer que vous savez ce que vous faites depuis que vous avez choisi d'utiliser l'arithmétique non signée. En outre, les nombres négatifs comme -1 peuvent souvent représenter quelque chose d'utile, comme un champ ignoré/defouted / unset alors que si vous utilisiez unsigné vous devez réserver une valeur particulière comme 2^32 - 1 ou quelque chose de similaire.

il y a longtemps, lorsque la mémoire était limitée et que les processeurs ne fonctionnaient pas automatiquement sur 64 bits à la fois, chaque bit comptait beaucoup plus, de sorte que le fait d'avoir signé vs octets ou shorts non signés comptait beaucoup plus souvent et était évidemment la bonne décision de conception. Aujourd'hui, utiliser un int signé est plus que suffisant dans presque tous les cas de programmation régulière, et si votre programme a vraiment besoin d'utiliser des valeurs plus grand que 2^31 - 1, vous voulez souvent juste un long de toute façon. Une fois que vous êtes dans le territoire de l'utilisation de longs, il est encore plus difficile de trouver une raison pour laquelle vous ne pouvez vraiment pas vous en sortir avec 2^63 - 1 entiers positifs. Chaque fois que nous allons à des processeurs 128 bits, ce sera encore moins un problème.

3
répondu Jonathan 2016-11-01 19:13:40

parce que le type unsigned est un mal pur.

le fait que dans C unsigned - int produit unsigned est encore plus mal.

voici un instantané du problème qui m'a brûlé plus d'une fois:

// We have odd positive number of rays, 
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );

// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
    // Compute the angle between nth ray and the middle one.
    // The index of the middle one is (rays.size() - 1) / 2,
    // the rays are evenly spaced at angle delta, therefore
    // the magnitude of the angle between nth ray and the 
    // middle one is: 
    double angle = delta * fabs( n - (rays.size() - 1) / 2 ); 

    // Do something else ...
}

avez-vous remarqué le bug? J'avoue que je ne l'ai vu qu'après avoir marché avec le débogueur.

parce que n est de type non signé size_t l'expression entière n - (rays.size() - 1) / 2 est évalué comme unsigned . Cette expression est destinée à être un signé position du n TH ray du milieu: le premier rayon du milieu sur le côté gauche aurait la position -1, le premier sur la droite aurait la position +1, etc. Après avoir pris la valeur de abs et multiplié par l'angle delta j'obtiendrais l'angle entre n TH ray et le milieu.

malheureusement pour moi ce qui précède l'expression contient le mal non signé et au lieu d'évaluer à, disons, -1, Il évalué à 2^32-1. La conversion subséquente en double a scellé le bogue.

après un bug ou deux causé par une mauvaise utilisation de unsigned arithmétique on doit commencer à se demander si le morceau supplémentaire qu'on obtient vaut la peine de la peine supplémentaire. J'essaie, autant que possible, d'éviter toute utilisation des types unsigned en arithmétique, bien qu'il l'utilise encore pour des opérations non-arithmétiques telles que les opérations binaires masque.

2
répondu Michael 2016-02-02 22:36:56

votre question est "pourquoi Java ne supporte-t-il pas les ints non signés"?

Et ma réponse à votre question est que Java veut que tous les types primitifs: octet , char , court , int et long doivent être traités comme des octet , mot , dword et qword respectivement, exactement comme dans l'assemblage , et les opérateurs Java sont signés opérations sur tous ses types primitifs à l'exception de char , mais seulement sur char ils ne sont pas signés 16 bits.

donc les méthodes statiques suppose être le non signé opérations aussi pour les deux 32 et 64 bits.

vous avez besoin de classe finale, dont les méthodes statiques peuvent être appelé pour les opérations non signé .

vous pouvez créer cette classe finale, l'appeler quel que soit le nom que vous voulez et mettre en œuvre ses méthodes statiques.

si vous ne savez pas comment mettre en œuvre les méthodes statiques, alors ce" lien peut vous aider.

à mon avis, Java est pas similaire à C++ du tout , si elle ni supporte les types non signés nor surcharge de l'opérateur, donc je pense que Java devrait être traité comme un langage complètement différent de C++ et de C.

Il est également totalement différentes dans le nom des langues.

donc je ne recommande pas en Java de taper du code similaire à C et je ne recommande pas de taper du code similaire à C++ du tout, parce que dans Java vous ne serez pas en mesure de faire ce que vous voulez faire ensuite C++, i.e. le code ne va pas continuer à être C++ comme du tout et pour moi c'est mauvais de coder comme ça, pour changer le style au milieu.

je recommande d'écrire et d'utiliser des méthodes statiques aussi pour les opérations signées, de sorte que vous ne voyez pas dans le code mélange d'opérateurs et de méthodes statiques pour les opérations signées et non signées, à moins que vous n'ayez besoin que des opérations signées dans le code, et il est normal d'utiliser les opérateurs seulement.

aussi je recommande d'éviter d'utiliser court , int et long types primitifs, et l'utilisation mot , dword et qword , respectivement, au lieu de cela, et vous êtes sur le point d'appeler les méthodes statiques pour les opérations et/ou des opérations signées au lieu d'utiliser les opérateurs.

si vous êtes sur le point de faire des opérations signées seulement et d'utiliser les opérateurs seulement dans le code, alors c'est d'accord pour l'utilisation de ces types primitifs court , int et long .

en fait mot , dword et qword do n't existent dans la langue, mais vous pouvez créer une nouvelle classe pour chacun et la mise en œuvre de chacun devrait être très facile:

la classe le mot contient le type primitif court seulement, la classe dword détient le type primitif int et la classe qword détient le type primitif long . Maintenant toutes les méthodes non signées et signées aussi statiques ou pas que votre choix, vous pouvez implémenter dans chaque classe, c'est-à-dire toutes les opérations 16 bits non signées et signées en donnant des noms de sens sur la classe word , toutes les opérations 32 bits opérations non signées et signées en donnant le sens des noms sur la classe dword et toutes les opérations 64 bits non signées et signées en donnant le sens des noms sur la classe qword .

si vous n'aimez pas donner trop de noms différents pour chaque méthode, vous pouvez toujours utiliser la surcharge en Java, bon à lire que Java a fait n't supprimer cela aussi!

si vous voulez des méthodes plutôt que opérateurs pour les opérations 8 bits signées et les méthodes pour les opérations 8 bits non signées qui n'ont pas d'opérateurs du tout, alors vous pouvez créer la classe Byte (notez que la première lettre "B" est capital, donc ce n'est pas le type primitif byte ) et mettre en œuvre les méthodes dans cette classe.

concernant le passage par valeur et le passage par référence:

si Je ne me trompe pas, comme dans C#, les objets primitifs sont passés par valeur naturellement, la classe mais les objets sont passés par référence naturellement, ce qui signifie que les objets de type Octet , mot , dword et qword sera passé par référence et non par valeur par défaut. J'aimerais que Java ait des objets struct comme C# has, donc tous les Octet , mot , dword et qword pourrait être implémenté pour être struct au lieu de class , donc par défaut ils ont été passés par valeur et non par référence par défaut, comme n'importe quel objet struct dans C#, comme les types primitifs, sont passés par valeur et non par référence par défaut, mais parce que Java est pire que C# et nous devons traiter avec cela, alors il n'y a que des classes et des interfaces, qui sont passées par référence et non par valeur par défaut. Donc, si vous voulez passer Octet , mot , dword et qword des objets par valeur et non par référence, comme n'importe quel autre objet de classe en Java et aussi en C#, vous devez simplement utiliser le constructeur de copie et c'est tout.

C'est la seule solution à laquelle je peux penser. J'aimerais juste pouvoir taper les types primitifs à word, dword et qword, mais Java ne supporte pas typedef et n'utilise pas du tout, contrairement à C # that supporte en utilisant , ce qui est équivalent au type C de CEF.

à propos de la sortie:

pour le même séquence de bits , vous pouvez les imprimer de plusieurs façons: en binaire, en décimal (comme la signification de %u dans C printf), en octal (comme la signification de %o dans C printf), en hexadécimal (comme la signification de %x dans C printf) et en entier (comme la signification du %D dans C printf).

noter que C printf ne connaît pas le type des variables passées comme paramètres à la fonction, donc printf connaît le type de chaque variable seulement à partir de l'objet char* passé au premier paramètre de la fonction.

dans chacune des classes: Octet , mot , dword et qword , vous pouvez implémenter la méthode d'impression et d'obtenir la fonctionnalité de printf, même si le type primitif de la la classe est signée, vous pouvez toujours l'imprimer comme non signée en suivant un algorithme impliquant des opérations logiques et de décalage pour obtenir les chiffres à imprimer à la sortie.

malheureusement le lien que je vous ai donné ne montre pas comment mettre en œuvre ces méthodes d'impression, mais je suis sûr que vous pouvez google pour les algorithmes dont vous avez besoin pour mettre en œuvre ces méthodes d'impression.

C'est tout ce que je peux répondre à votre question et vous suggérer.

2
répondu Farewell Stack Exchange 2017-08-07 12:16:49

je peux penser à un effet secondaire malheureux. Dans les bases de données Java embedded, le nombre d'ids que vous pouvez avoir avec un champ d'id 32bit est 2^31, pas 2^32 (~2 milliards, pas ~4 milliards).

-2
répondu mike g 2009-01-11 23:56:55

la raison pour laquelle IMHO est parce qu'ils sont/étaient trop paresseux pour mettre en œuvre/corriger cette erreur. Suggérant que les programmeurs C / C++ ne comprennent pas non signé, structure, union, Bit flag... Est juste absurde.

éther vous parliez avec un programmeur basic/bash/java sur le point de commencer à programmer A LA C, sans aucune connaissance réelle de ce langage ou vous parlez simplement de votre propre esprit. ;)

quand vous négociez tous les jours sur le format soit à partir du fichier ou du matériel, vous commencez à vous demander ce qu'ils pensaient.

Un bon exemple serait d'utiliser un octet non signé comme un tournant en boucle. Pour ceux d'entre vous qui ne comprennent pas la dernière phrase, Comment diable vous appelez-vous un programmeur.

DC

-6
répondu Denis Co 2012-03-10 21:37:56