Warum verwendet die Java-API int anstelle von short oder byte?

137

Warum wird die Java-API verwendet int, wenn shortoder sogar byteausreichend?

Beispiel: Das DAY_OF_WEEKFeld in der Klasse Calendarverwendet int.

Wenn der Unterschied zu gering ist, warum existieren diese Datentypen ( short, int) überhaupt?

Willi Mentzel
quelle

Antworten:

166

Einige der Gründe wurden bereits aufgezeigt. Zum Beispiel die Tatsache, dass "... (fast) alle Operationen auf Byte, kurz, diese Grundelemente auf int heraufstufen" . Die naheliegende nächste Frage wäre jedoch: WARUM werden diese Typen befördert int?

Um noch eine Ebene tiefer zu gehen: Die Antwort kann sich einfach auf den Java Virtual Machine-Befehlssatz beziehen. Wie in der Tabelle in der Java Virtual Machine-Spezifikation zusammengefasst , sind alle integralen arithmetischen Operationen wie Hinzufügen, Teilen und andere nur für den Typ intund den Typ verfügbar longund nicht für die kleineren Typen.

(Nebenbei: Die kleineren Typen ( byteund short) sind grundsätzlich nur für Arrays vorgesehen . Ein Array wie benötigt new byte[1000]1000 Bytes und ein Array wie new int[1000]4000 Bytes.)

Jetzt könnte man natürlich sagen: "... die naheliegende nächste Frage wäre: WARUM werden diese Anweisungen nur für int(und long) angeboten?" .

Ein Grund wird in der oben genannten JVM-Spezifikation erwähnt:

Wenn jede eingegebene Anweisung alle Laufzeitdatentypen der Java Virtual Machine unterstützen würde, gäbe es mehr Anweisungen, als in einem Byte dargestellt werden könnten

Darüber hinaus kann die Java Virtual Machine als Abstraktion eines realen Prozessors betrachtet werden. Die Einführung einer dedizierten arithmetischen Logikeinheit für kleinere Typen wäre die Mühe nicht wert: Sie würde zusätzliche Transistoren benötigen, könnte aber immer noch nur eine Addition in einem Taktzyklus ausführen. Die dominierende Architektur bei der Entwicklung der JVM war 32 Bit, genau richtig für 32 Bit int. (Die Operationen, die einen 64-Bit- longWert beinhalten, werden als Sonderfall implementiert.)

(Hinweis: Der letzte Absatz ist unter Berücksichtigung einer möglichen Vektorisierung usw. etwas vereinfacht, sollte jedoch die Grundidee vermitteln, ohne zu tief in die Themen des Prozessordesigns einzutauchen.)


EDIT: Ein kurzer Nachtrag, der sich auf das Beispiel aus der Frage konzentriert, aber allgemeiner: Man könnte auch fragen, ob es nicht vorteilhaft wäre, Felder mit den kleineren Typen zu speichern . Zum Beispiel könnte man denken, dass Speicher durch Speichern Calendar.DAY_OF_WEEKals gespeichert werden könnte byte. Hier kommt jedoch das Java-Klassendateiformat ins Spiel: Alle Felder in einer Klassendatei belegen mindestens einen "Steckplatz" mit der Größe eins int(32 Bit). (Die "breiten" Felder doubleund longbelegen zwei Steckplätze). Wenn Sie also ein Feld explizit als Speicher deklarieren shortoder bytenicht speichern.

Marco13
quelle
Ich würde vermuten, dass die Logik, warum Operanden zu int befördert werden, auch mit der in C und C ++
Shafik Yaghmour
@ Marco13 "Wenn Sie also ein Feld explizit als kurz oder byte deklarieren, wird auch kein Speicherplatz gespart." ist das wahr? Ich denke nicht, dass das richtig ist.
ACV
@ACV Streng genommen könnte eine Implementierung ein kompakteres Formular speichern, aber das Format, das "virtuell" verfügbar gemacht wird (dh von der virtuellen Maschine), behandelt die Werte als mindestens so groß wie int. Wenn Sie einen Verweis auf eine andere Implementierung haben, würde ich die Antwort aktualisieren und den Link entsprechend einfügen.
Marco13
40

(Fast) Alle Operationen auf byte, shortfördert sie intzum Beispiel, können Sie nicht schreiben:

short x = 1;
short y = 2;

short z = x + y; //error

Arithmetik ist einfacher und unkomplizierter bei der Verwendung int, es muss nicht gegossen werden.

In Bezug auf den Platz macht es einen sehr kleinen Unterschied. byteund shortwürde die Dinge komplizieren, ich denke nicht, dass sich diese Mikrooptimierung lohnt, da es sich um eine feste Anzahl von Variablen handelt.

byteist relevant und nützlich, wenn Sie für eingebettete Geräte programmieren oder mit Dateien / Netzwerken arbeiten. Auch diese Grundelemente sind begrenzt. Was ist, wenn die Berechnungen in Zukunft ihre Grenzen überschreiten könnten? Versuchen Sie, über eine Erweiterung für die CalendarKlasse nachzudenken , die möglicherweise größere Zahlen entwickelt.

Beachten Sie auch , dass in einem 64-Bit - Prozessoren, werden die Einheimischen in den Registern gespeichert und keine Ressourcen verwenden, so verwenden int, shortund andere Primitiven werden keinen Unterschied überhaupt machen. Darüber hinaus richten viele Java-Implementierungen Variablen * (und Objekte) aus.


* byte Und shortnehmen den gleichen Raum wie intwenn sie lokale Variablen, Klassenvariablen oder sogar Instanz Variablen. Warum? Da in (den meisten) Computersystemen die Variablenadressen ausgerichtet sind. Wenn Sie beispielsweise ein einzelnes Byte verwenden, erhalten Sie tatsächlich zwei Bytes - eines für die Variable selbst und eines für das Auffüllen.

byteNehmen Sie andererseits in Arrays 1 Byte, short2 Bytes und intvier Bytes, da in Arrays nur der Anfang und möglicherweise das Ende ausgerichtet werden müssen. Dies macht einen Unterschied, wenn Sie zum Beispiel verwenden möchten System.arraycopy(), dann werden Sie wirklich einen Leistungsunterschied feststellen.

Maroun
quelle
1
Unterhaltsame Tatsache: Wenn Sie für beide Werte endgültige Modifikatoren verwenden, funktioniert dies. :)
Alexander
7

Weil arithmetische Operationen bei der Verwendung von ganzen Zahlen im Vergleich zu Kurzschlüssen einfacher sind. Angenommen, die Konstanten wurden tatsächlich durch shortWerte modelliert . Dann müssten Sie die API folgendermaßen verwenden:

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

Beachten Sie das explizite Casting. Kurzwerte werden implizit zu intWerten heraufgestuft, wenn sie in arithmetischen Operationen verwendet werden. (Auf dem Operandenstapel werden Kurzschlüsse sogar als Ints ausgedrückt.) Die Verwendung wäre ziemlich umständlich, weshalb intWerte für Konstanten häufig bevorzugt werden.

Im Vergleich dazu ist der Gewinn an Speichereffizienz minimal, da nur eine feste Anzahl solcher Konstanten existiert. Wir sprechen von 40 Konstanten. Wenn Sie den Speicher von intauf shortändern, werden Sie sicher sein 40 * 16 bit = 80 byte. Siehe diese Antwort als weitere Referenz.

Rafael Winterhalter
quelle
5

Wenn Sie die Philosophie verwenden, bei der integrale Konstanten in dem kleinsten Typ gespeichert werden, in den sie passen, hat Java ein ernstes Problem: Wenn Programmierer Code mit integralen Konstanten schreiben, müssen sie sorgfältig auf ihren Code achten, um zu überprüfen, ob der Typ von Die Konstanten sind wichtig. Wenn ja, schlagen Sie den Typ in der Dokumentation nach und / oder führen Sie die erforderlichen Typkonvertierungen durch.

Welche Vorteile können Sie mit dieser Philosophie erhoffen, nachdem wir ein ernstes Problem skizziert haben? Ich wäre nicht überrascht, wenn der einzige zur Laufzeit beobachtbare Effekt dieser Änderung der Typ wäre, den Sie erhalten, wenn Sie die Konstante durch Reflexion nachschlagen. (und natürlich alle Fehler, die von faulen / unwissenden Programmierern eingeführt werden, die die Typen der Konstanten nicht korrekt berücksichtigen)

Das Abwägen der Vor- und Nachteile ist sehr einfach: Es ist eine schlechte Philosophie.


quelle
4

Die Entwurfskomplexität einer virtuellen Maschine hängt davon ab, wie viele Arten von Vorgängen sie ausführen kann. Es ist einfacher, vier Implementierungen eines Befehls wie "Multiplizieren" zu haben - jeweils eine für 32-Bit-Ganzzahl, 64-Bit-Ganzzahl, 32-Bit-Gleitkomma und 64-Bit-Gleitkomma - als zusätzlich zu den oben genannten auch Versionen für die kleineren numerischen Typen. Eine interessantere Entwurfsfrage ist, warum es vier Typen geben sollte, anstatt weniger (alle Ganzzahlberechnungen mit 64-Bit-Ganzzahlen durchführen und / oder alle Gleitkommaberechnungen mit 64-Bit-Gleitkommawerten durchführen). Der Grund für die Verwendung von 32-Bit-Ganzzahlen besteht darin, dass Java auf vielen Plattformen ausgeführt werden sollte, auf denen 32-Bit-Typen genauso schnell wie 16-Bit- oder 8-Bit-Typen verarbeitet werden können, Operationen mit 64-Bit-Typen jedoch spürbar sind Langsamer.nur mit 32-Bit-Typen.

Bei der Durchführung von Gleitkommaberechnungen mit 32-Bit-Werten liegen die Vorteile etwas weniger auf der Hand. Es gibt einige Plattformen, auf denen eine Berechnung gefälltfloat a=b+c+d;Dies kann am schnellsten durchgeführt werden, indem alle Operanden in einen Typ mit höherer Genauigkeit konvertiert, hinzugefügt und das Ergebnis dann zur Speicherung wieder in eine 32-Bit-Gleitkommazahl konvertiert werden. Es gibt andere Plattformen, auf denen es effizienter wäre, alle Berechnungen mit 32-Bit-Gleitkommawerten durchzuführen. Die Entwickler von Java entschieden, dass alle Plattformen die gleichen Schritte ausführen sollten und dass sie die Hardwareplattformen bevorzugen sollten, für die 32-Bit-Gleitkommaberechnungen schneller sind als längere, obwohl dieser PC sowohl die Geschwindigkeit stark verschlechterte und Präzision der Gleitkomma-Mathematik auf einem typischen PC sowie auf vielen Maschinen ohne Gleitkommaeinheiten. Beachten Sie übrigens, dass abhängig von den Werten von b, c und d Zwischenberechnungen mit höherer Genauigkeit verwendet werden, wenn Ausdrücke wie die oben genannten berechnet werdenfloat a=b+c+d;liefert manchmal Ergebnisse, die wesentlich genauer sind, als dies bei allen Zwischenoperanden der Fall wäre, die mit floatGenauigkeit berechnet wurden , liefert aber manchmal einen Wert, der ein wenig weniger genau ist. In jedem Fall entschied Sun, dass alles auf die gleiche Weise erfolgen sollte, und entschied sich für die Verwendung von floatWerten mit minimaler Genauigkeit .

Beachten Sie, dass die Hauptvorteile kleinerer Datentypen offensichtlich werden, wenn eine große Anzahl von ihnen zusammen in einem Array gespeichert wird. Selbst wenn es keinen Vorteil hätte, einzelne Variablen von Typen zu haben, die kleiner als 64 Bit sind, lohnt es sich, Arrays zu haben, die kleinere Werte kompakter speichern können. Wenn eine lokale Variable eher eine byteals eine ist, werden longsieben Bytes gespeichert. Ein Array mit 1.000.000 Nummern enthält jede Nummer als a byteund nicht alslongWellen 7.000.000 Bytes. Da jeder Array-Typ nur wenige Vorgänge unterstützen muss (insbesondere ein Element lesen, ein Element speichern, einen Bereich von Elementen innerhalb eines Arrays kopieren oder einen Bereich von Elementen von einem Array in ein anderes kopieren), erhöht sich die Komplexität, mehr zu haben Array-Typen sind nicht so schwerwiegend wie die Komplexität, mehr Typen direkt verwendbarer diskreter numerischer Werte zu haben.

Superkatze
quelle
2

Eigentlich hätte es einen kleinen Vorteil. Wenn Sie eine haben

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

Dann benötigt eine typische JVM so viel Speicherplatz wie eine Klasse, die eine einzelne enthält int. Der Speicherverbrauch wird auf ein nächstes Vielfaches von 8 oder 16 Bytes gerundet (IIRC, das konfigurierbar ist), so dass die Fälle, in denen tatsächlich gespart wird, eher selten sind.

Diese Klasse wäre etwas einfacher zu verwenden, wenn die entsprechenden CalendarMethoden a zurückgeben würden byte. Aber es gibt keine solche CalendarMethoden, nur get(int)die Zusammenarbeit soll kehrt ein intwegen anderen Bereichen. Jede Operation bei kleineren Typen fördert zu int, so dass Sie viel Casting benötigen.

Höchstwahrscheinlich geben Sie entweder auf und wechseln zu einem intoder schreiben Setter wie

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

Dann spielt die Art DAY_OF_WEEKsowieso keine Rolle.

Maaartinus
quelle