it-swarm.com.de

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

Warum verwendet die Java API int, wenn short oder sogar byte ausreichen würde?

Beispiel: Die DAY_OF_WEEK Feld in Klasse Calendar verwendet int.

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

134
Willi Mentzel

Auf einige der Gründe wurde bereits hingewiesen. Zum Beispiel wird die Tatsache, dass "... (Fast) Alle Operationen auf Byte, kurz, diese Primitive zu int" befördern . Die naheliegende nächste Frage wäre jedoch: [~ # ~] warum [~ # ~] werden diese Typen zu int befördert?

Um eine Ebene tiefer zu gehen: Die Antwort kann sich einfach auf den Befehlssatz Java= Virtual Machine beziehen. Wie in der Tabelle in Java) zusammengefasst = Virtual Machine Specification , Alle integralen Rechenoperationen wie Addieren, Dividieren und andere sind nur für den Typ int verfügbar. und der Typ long und nicht für die kleineren Typen.

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

Nun könnte man natürlich sagen, dass "... die naheliegende nächste Frage wäre: [~ # ~] warum [~ # ~] Werden diese Anweisungen nur für int (und long) angeboten? ".

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

Wenn jede getippte Anweisung alle Laufzeitdatentypen der Java Virtual Machine unterstützt, würde es mehr Anweisungen geben, 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 von dediziertem Arithmetic Logic Unit für kleinere Typen wäre den Aufwand nicht wert: Es würde zusätzliche Transistoren benötigen, aber es konnte immer noch nur eine Addition in einem Taktzyklus ausgeführt werden. Die dominierende Architektur beim Entwurf der JVM war 32 Bit, genau richtig für ein 32 Bit int. (Die Operationen, die ein 64 Bit long werden als Sonderfall implementiert).

(Hinweis: Der letzte Absatz ist etwas vereinfacht, unter Berücksichtigung möglicher Vektorisierung usw., 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 ausgedrückt: Man könnte auch fragen, ob es nicht vorteilhaft wäre, Felder mit den kleineren Typen zu speichern. Beispielsweise könnte man meinen, dass Speicherplatz gespart werden könnte, indem Calendar.DAY_OF_WEEK Als byte gespeichert wird. Aber hier kommt das Java Class File Format ins Spiel: Alle Felder in einer Klassendatei belegen mindestens einen "Slot", der die Größe eins hat int (32 Bit) (Die "breiten" Felder double und long belegen zwei Slots.) Deklarieren Sie ein Feld also explizit als short oder byte würde auch keinen Speicher speichern.

164
Marco13

(Fast) Alle Operationen auf byte, short werden zu int hochgestuft. Sie können beispielsweise nicht schreiben:

short x = 1;
short y = 2;

short z = x + y; //error

Arithmetik ist einfacher und unkomplizierter, wenn int verwendet wird, ohne dass eine Umwandlung erforderlich ist.

In Bezug auf den Platz macht es einen sehr kleinen Unterschied. byte und short würden die Dinge komplizieren, ich halte diese Mikrooptimierung nicht für lohnenswert, da es sich um eine feste Anzahl von Variablen handelt.

byte ist 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 Klasse Calendar nachzudenken, die möglicherweise größere Zahlen ergibt.

Beachten Sie auch, dass in 64-Bit-Prozessoren die lokalen Elemente in Registern gespeichert werden und keine Ressourcen verwenden. Die Verwendung von int, short und anderen Grundelementen macht also keinen Unterschied . Darüber hinaus richten viele Java Implementierungen Variablen aus* (und Objekte).


* byte und short belegen denselben Platz wie int, wenn es sich um lokale Variablen, Klasse Variablen oder sogar - handelt. Instanz Variablen. Warum? Da in (den meisten) Computersystemen die Adressen von Variablen ausgerichtet sind, erhalten Sie beispielsweise bei Verwendung eines einzelnen Bytes zwei Bytes - eines für die Variable selbst und eines für das Auffüllen .

Auf der anderen Seite nehmen in Arrays byte 1 Byte, short 2 Byte und int vier Byte, weil in Arrays nur der Anfang und vielleicht das Ende davon muss ausgerichtet werden. Dies macht einen Unterschied, wenn Sie beispielsweise System.arraycopy() verwenden möchten, dann werden Sie wirklich einen Leistungsunterschied feststellen.

39
Maroun

Weil arithmetische Operationen bei Verwendung von Ganzzahlen im Vergleich zu Shorts einfacher sind. Angenommen, die Konstanten wurden tatsächlich durch short Werte 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. Kurze Werte werden implizit zu int Werten heraufgestuft, wenn sie in arithmetischen Operationen verwendet werden. (Auf dem Operandenstapel werden Kurzschlüsse sogar als Ints ausgedrückt.) Dies wäre recht umständlich, weshalb für Konstanten häufig int -Werte 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 int in short ändern, können Sie 40 * 16 bit = 80 byte. Siehe diese Antwort für weitere Referenz.

7

Wenn Sie die Philosophie verwendet haben, bei der integrale Konstanten in dem kleinsten Typ gespeichert werden, in den sie passen, dann hätte Java) ein ernstes Problem: Wenn Programmierer Code mit integralen Konstanten schreiben, müssen sie vorsichtig sein Überprüfen Sie anhand des Codes, ob der Typ der Konstanten von Bedeutung ist, und suchen Sie in der Dokumentation nach dem Typ, und/oder führen Sie die erforderlichen Typkonvertierungen durch.

Nun, da wir ein ernstes Problem skizziert haben, welche Vorteile könnten Sie mit dieser Philosophie erhoffen? Es würde mich nicht wundern, wenn der zur Laufzeit beobachtbare Effekt dieser Änderung nur der Typ wäre, den Sie erhalten, wenn Sie die Konstante über Reflektion nachschlagen. (und natürlich alle Fehler, die von faulen/unwissenden Programmierern verursacht werden, die die Typen der Konstanten nicht korrekt berücksichtigen)

Das Für und Wider abzuwägen ist sehr einfach: Es ist eine schlechte Philosophie.

5
Hurkyl

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-Ganzzahlen, 64-Bit-Ganzzahlen, 32-Bit-Gleitkommazahlen und 64-Bit-Gleitkommazahlen - als zusätzlich zu den obigen Versionen auch für die kleineren numerischen Typen. Eine interessantere Entwurfsfrage ist, warum es eher vier als weniger Typen geben sollte (Ausführen aller Ganzzahlberechnungen mit 64-Bit-Ganzzahlen und/oder Ausführen aller Gleitkommaberechnungen mit 64-Bit-Gleitkommawerten). Der Grund für die Verwendung von 32-Bit-Ganzzahlen ist, dass erwartet wurde, dass Java auf vielen Plattformen ausgeführt wird, auf denen 32-Bit-Typen genauso schnell verarbeitet werden können wie 16-Bit- oder 8-Bit-Typen, aber Operationen mit 64-Bit-Typen wären merklich langsamer. Selbst auf Plattformen, auf denen 16-Bit-Typen schneller zu verarbeiten sind, würden die zusätzlichen Kosten für die Arbeit mit 32-Bit-Mengen durch die Einfachheit von nur mit 32-Bit-Typen.

Bei der Ausführung von Gleitkommaberechnungen mit 32-Bit-Werten liegen die Vorteile etwas weniger auf der Hand. Es gibt einige Plattformen, auf denen eine Berechnung wie float a=b+c+d; kann am schnellsten ausgeführt werden, indem alle Operanden in einen Typ mit höherer Genauigkeit konvertiert werden, diese hinzugefügt werden und das Ergebnis dann zur Speicherung in eine 32-Bit-Gleitkommazahl zurückkonvertiert wird. Auf anderen Plattformen wäre es effizienter, alle Berechnungen mit 32-Bit-Gleitkommawerten durchzuführen. Die Entwickler von Java) haben entschieden, dass alle Plattformen die gleichen Schritte ausführen müssen und dass sie die Hardware-Plattformen bevorzugen sollten, für die 32-Bit-Gleitkommaberechnungen schneller sind als längere. obwohl dieser PC sowohl die Geschwindigkeit als auch die Präzision der Gleitkomma-Mathematik auf einem typischen PC wie auch auf vielen Maschinen ohne Gleitkomma-Einheiten stark verschlechterte. Verwenden von Zwischenberechnungen mit höherer Genauigkeit bei der Berechnung von Ausdrücken wie dem oben genannten float a=b+c+d; liefert manchmal Ergebnisse, die wesentlich genauer sind, als dies bei allen Zwischenoperanden der Fall wäre, die mit float Genauigkeit berechnet wurden, liefert aber manchmal einen Wert, der ein kleines bisschen ungenauer ist. In jedem Fall entschied Sun, dass alles auf die gleiche Weise erfolgen sollte, und entschied sich für die Verwendung von float Werten 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 gab, einzelne Variablen mit einem Typ kleiner als 64 Bit zu haben, lohnt es sich, Arrays zu haben, die kleinere Werte kompakter speichern können. Wenn eine lokale Variable ein byte anstelle eines long ist, werden sieben Bytes gespart. Ein Array mit 1.000.000 Zahlen enthält jede Zahl als byte und nicht als long und bewegt 7.000.000 Bytes. Da jeder Array-Typ nur wenige Operationen unterstützen muss (insbesondere ein Element lesen, ein Element speichern, einen Bereich von Elementen in einem Array 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.

4
supercat

Eigentlich gäbe es einen kleinen Vorteil. Wenn Sie eine haben

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

in einer typischen JVM benötigt sie genauso viel Platz wie eine Klasse, die ein einzelnes int enthält. Der Speicherverbrauch wird auf ein nächstes Vielfaches von 8 oder 16 Bytes gerundet (IIRC, das ist konfigurierbar), so dass die Fälle, in denen wirklich gespart wird, eher selten sind.

Diese Klasse wäre etwas einfacher zu verwenden, wenn die entsprechenden Methoden Calendar ein byte zurückgeben würden. Es gibt jedoch keine derartigen Calendar Methoden, sondern nur get(int), die wegen anderer Felder ein int zurückgeben müssen. Jede Operation bei kleineren Typen wird zu int befördert, sodass Sie viel Casting benötigen.

Höchstwahrscheinlich werden Sie entweder aufgeben und zu einem int wechseln oder Setter wie schreiben

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

Dann spielt die Art von DAY_OF_WEEK Sowieso keine Rolle.

2
maaartinus