it-swarm.com.de

Primitiver Typ 'short' - Casting in Java

Ich habe eine Frage zum primitiven Typ short in Java. Ich benutze JDK 1.6.

Wenn ich folgendes habe:

short a = 2;
short b = 3;
short c = a + b;

der Compiler will nicht kompilieren - er sagt, dass er "nicht von int nach short konvertieren kann" und schlägt vor, dass ich eine Umwandlung nach short vornehme.

short c = (short) (a + b);

funktioniert wirklich. Aber meine Frage ist, warum ich casten muss? Die Werte von a und b liegen im Bereich von short - der Bereich der Kurzwerte beträgt {-32.768, 32767}. Ich muss auch casten, wenn ich die Operationen ausführen möchte -, *,/(ich habe nicht nach anderen gesucht).

Wenn ich dasselbe für den primitiven Typ int mache, muss ich aa + bb nicht in int umwandeln. Folgendes funktioniert gut:

int aa = 2;
int bb = 3;
int cc = aa +bb;

Ich habe dies beim Entwerfen einer Klasse entdeckt, in der ich zwei Variablen vom Typ short hinzufügen musste, und der Compiler wollte, dass ich eine Besetzung mache. Wenn ich dies mit zwei Variablen vom Typ int mache, muss ich keine Umwandlung vornehmen.

Eine kleine Bemerkung: Dasselbe passiert auch mit dem primitiven Typ byte. Das funktioniert also:

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

aber das nicht:

byte a = 2;
byte b = 3;
byte c = a + b;

Für long, float, double und int ist keine Umwandlung erforderlich. Nur für short und byte Werte.

75
user42155

Wie in kurzes C # erklärt (aber auch für andere Sprachcompiler wie Java)

Es gibt eine vordefinierte implizite Konvertierung von short nach int, long, float, double oder decimal.

Sie können nichtliterale numerische Typen mit größerer Speichergröße nicht implizit in kurze Typen konvertieren (Informationen zu den Speichergrößen integraler Typen finden Sie in der Tabelle Integraler Typen). Betrachten Sie zum Beispiel die folgenden beiden kurzen Variablen x und y:

short x = 5, y = 12;

Die folgende Zuweisungsanweisung erzeugt einen Kompilierungsfehler , da der arithmetische Ausdruck auf der rechten Seite des Zuweisungsoperators standardmäßig als int ausgewertet wird.

short z = x + y;   // Error: no conversion from int to short

Verwenden Sie eine Besetzung, um dieses Problem zu beheben:

short z = (short)(x + y);   // OK: explicit conversion

Es ist jedoch möglich, die folgenden Anweisungen zu verwenden, wenn die Zielvariable dieselbe Speichergröße oder eine größere Speichergröße hat:

int m = x + y;
long n = x + y;

Eine gute Anschlussfrage ist:

msgstr "Warum wird der arithmetische Ausdruck auf der rechten Seite des Zuweisungsoperators standardmäßig zu int ausgewertet?"

Eine erste Antwort finden Sie in:

Klassifizieren und formales Überprüfen der ganzzahligen konstanten Faltung

Die Java-Sprachspezifikation definiert genau, wie Ganzzahlen dargestellt werden und wie ganzzahlige arithmetische Ausdrücke ausgewertet werden sollen . Dies ist eine wichtige Eigenschaft von Java, da diese Programmiersprache für die Verwendung in verteilten Anwendungen im Internet entwickelt wurde. Ein Java Programm ist erforderlich, um das gleiche Ergebnis unabhängig von der Zielmaschine zu erzielen, die es ausführt .

Im Gegensatz dazu ist C (und die Mehrheit der weit verbreiteten imperativen und objektorientierten Programmiersprachen) schlampiger und lässt viele wichtige Merkmale offen. Die Absicht hinter dieser ungenauen Sprachspezifikation ist klar. Dieselben C-Programme sollen auf einer 16-Bit-, 32-Bit- oder sogar 64-Bit-Architektur ausgeführt werden, indem die Ganzzahlarithmetik der Quellprogramme mit den im Zielprozessor integrierten Rechenoperationen instanziiert wird. Dies führt zu wesentlich effizienterem Code, da die verfügbaren Maschinenoperationen direkt verwendet werden können. Solange die Ganzzahlberechnungen nur Zahlen behandeln, die "ausreichend klein" sind, treten keine Inkonsistenzen auf.

In diesem Sinne ist die C-Integer-Arithmetik ein Platzhalter, der nicht exakt durch die Programmiersprachenspezifikation definiert ist, sondern nur durch die Bestimmung der Zielmaschine vollständig instanziiert wird.

Java definiert genau, wie Ganzzahlen dargestellt werden und wie Ganzzahlarithmetik berechnet werden soll.

      Java Integers
--------------------------
Signed         |  Unsigned
--------------------------
long  (64-bit) |
int   (32-bit) |
short (16-bit) |  char (16-bit)
byte  (8-bit)  |

Char ist der einzige vorzeichenlose Integer-Typ. Seine Werte repräsentieren Unicode-Zeichen von \u0000 Bis \uffff, D. H. Von 0 bis 216−1.

Wenn ein Ganzzahloperator einen Operanden vom Typ long hat, wird der andere Operand ebenfalls in den Typ long konvertiert. Ansonsten wird die Operation an Operanden vom Typ int ausgeführt, ggf. werden kürzere Operanden in int konvertiert. Die Umrechnungsregeln sind genau festgelegt.

[Aus elektronischen Notizen in der Theoretischen Informatik 82 Nr. 2 (2003)]
Blesner-Blech-COCV 2003: Sabine GLESNER , Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Deutschland]

60
VonC

EDIT: Okay, jetzt wissen wir, dass es Java ist ...

Abschnitt 4.2.2 der Java Sprachspezifikation lautet:

Die Programmiersprache Java bietet eine Reihe von Operatoren, die auf ganzzahlige Werte einwirken:

[...]

  • Die numerischen Operatoren, die einen Wert vom Typ int oder long ergeben:
  • [...]
  • Die additiven Operatoren + und - (§15.18)

Mit anderen Worten, es ist wie in C # - der Additionsoperator (wenn er auf ganzzahlige Typen angewendet wird) führt immer nur zu int oder long, weshalb Sie eine Umwandlung vornehmen müssen, um ein short variable.

Originalantwort (C #)

In C # (Sie haben die Sprache nicht angegeben, ich vermute also) sind die einzigen Additionsoperatoren für primitive Typen:

int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);
float operator +(float x, float y);
double operator +(double x, double y);

Diese befinden sich in der C # 3.0-Spezifikation, Abschnitt 7.7.4. Zusätzlich wird die Dezimaladdition definiert:

decimal operator +(decimal x, decimal y);

(Aufzählungshinzufügung, Zeichenfolgenverkettung und Delegatenkombination werden dort ebenfalls definiert.)

Wie Sie sehen, gibt es keinen short operator +(short x, short y) -Operator - daher werden beide Operanden implizit in int konvertiert und das int-Formular wird verwendet. Das bedeutet, dass das Ergebnis ein Ausdruck vom Typ "int" ist und daher umgewandelt werden muss.

17
Jon Skeet

In C # und Java wird der arithmatische Ausdruck auf der rechten Seite der Zuweisung standardmäßig als int ausgewertet. Aus diesem Grund müssen Sie auf einen Short zurückgreifen, da es aus offensichtlichen Gründen keine implizite Konvertierungsform int zu short gibt.

16
Rik

Angesichts der Tatsache, dass die Frage "warum int standardmäßig" nicht beantwortet wurde ...

Erstens ist "default" nicht wirklich der richtige Begriff (obwohl nah genug). Wie von VonC festgestellt, hat ein Ausdruck aus Ints und Longs ein langes Ergebnis. Und eine Operation, die aus Ints/Logs und Doubles besteht, hat ein doppeltes Ergebnis. Der Compiler stuft die Ausdrücke eines Ausdrucks auf einen beliebigen Typ um, der einen größeren Bereich und/oder eine größere Genauigkeit im Ergebnis bietet (Gleitkommatypen haben vermutlich einen größeren Bereich und eine größere Genauigkeit als das Integral, obwohl die Genauigkeit bei der Konvertierung großer Longs in das Doppelte abnimmt).

Eine Einschränkung ist, dass diese Promotion nur für die Bedingungen stattfindet, die sie benötigen. Im folgenden Beispiel verwendet der Unterausdruck 5/4 also nur ganzzahlige Werte und wird unter Verwendung von Ganzzahl-Mathematik ausgeführt, obwohl der Gesamtausdruck ein Doppel enthält. Das Ergebnis entspricht nicht Ihren Erwartungen ...

(5/4) * 1000.0

OK, warum werden Byte und Short zu int befördert? Ohne Referenzen, die mich unterstützen, liegt es an der Praktikabilität: Es gibt eine begrenzte Anzahl von Bytecodes.

"Bytecode" verwendet, wie der Name schon sagt, ein einzelnes Byte, um eine Operation anzugeben. Zum Beispiel iadd , wodurch zwei Zoll hinzugefügt werden. Derzeit ist 205 Opcodes sind definiert und die Ganzzahl-Mathematik benötigt 18 für jeden Typ (dh insgesamt 36 zwischen Ganzzahl und Lang), wobei Konvertierungsoperatoren nicht berücksichtigt werden.

Wenn kurz und byteweise jeder seinen eigenen Satz von Opcodes hat, wären Sie bei 241, was die Erweiterungsfähigkeit der JVM einschränkt. Wie gesagt, es gibt keine Belege dafür, aber ich vermute, dass Gosling et al. Gesagt haben: "Wie oft benutzen die Leute tatsächlich Shorts?" Auf der anderen Seite führt das Heraufstufen des Bytes auf int zu diesem nicht so wunderbaren Effekt (die erwartete Antwort ist 96, die tatsächliche ist -16):

byte x = (byte)0xC0;
System.out.println(x >> 2);
7
kdgregory

Welche sprache sprichst du

Viele C-basierte Sprachen haben die Regel, dass jeder mathematische Ausdruck in der Größe int oder größer ausgeführt wird. Aus diesem Grund hat das Ergebnis nach dem Hinzufügen von zwei Shorts den Typ int. Dies macht eine Besetzung erforderlich.

5
Darron

Java verwendet für Berechnungen immer mindestens 32-Bit-Werte. Dies ist auf die 32-Bit-Architektur zurückzuführen, die 1995 bei der Einführung von Java eingeführt wurde. Die Registergröße in der CPU betrug 32 Bit, und die arithmetische Logikeinheit akzeptierte 2 Zahlen der Länge einer CPU Daher wurden die CPUs für diese Werte optimiert.

Dies ist der Grund, warum alle Datentypen, die arithmetische Operationen unterstützen und weniger als 32 Bit haben, nach int (32 Bit) konvertiert werden, sobald Sie sie für Berechnungen verwenden.

Zusammenfassend lässt sich sagen, dass dies hauptsächlich auf Leistungsprobleme zurückzuführen ist und heutzutage aus Gründen der Kompatibilität beibehalten wird.

2
Andreas Mennel

In Java ist jeder numerische Ausdruck wie folgt:

anyPrimitive zas = 1;
anyPrimitive bar = 3;
?? x = zas  + bar 

x ist immer mindestens ein int oder ein long, wenn eines der Additionselemente ein long ist.

Aber es gibt einige Macken

byte a = 1; // 1 is an int, but it won't compile if you use a variable
a += 2; // the shortcut works even when 2 is an int
a++; // the post and pre increment operator work
1
Jaime Hablutzel

AFAIS, niemand erwähnt die Verwendung von final dafür. Wenn Sie Ihr letztes Beispiel ändern und die Variablen a und b als final definieren, lautet der Compiler versichert, dass ihre Summe mit dem Wert 5 einer Variablen vom Typ byte ohne Genauigkeitsverlust zugewiesen werden kann . In diesem Fall kann der Compiler die Summe von a und b gut zu c zuordnen. Hier ist der geänderte Code:

final byte a = 2;
final byte b = 3;
byte c = a + b;
1
snr

Jeder Datentyp, der niedriger als "int" ist (außer Boolean), wird implizit in "int" konvertiert.

In Ihrem Fall:

short a = 2;
short b = 3;
short c = a + b;

Das Ergebnis von (a + b) wird implizit in ein int konvertiert. Und jetzt weisen Sie es "kurz" zu. So dass Sie den Fehler erhalten.

short, byte, char - für all diese werden wir den gleichen Fehler bekommen.

1

Ich möchte etwas hinzufügen, auf das nicht hingewiesen wurde. Java berücksichtigt nicht die Werte, die Sie den Variablen (2 und 3) in ...

kurz a = 2; kurz b = 3; kurzes c = a + b;

So weit wie Java weiß, könnten Sie dies tun ...

kurz a = 32767; kurz b = 32767; kurzes c = a + b;

Wenn dies außerhalb des Bereichs von short liegt, wird das Ergebnis automatisch in ein int umgewandelt, da es "möglich" ist, dass das Ergebnis mehr als ein short, aber nicht mehr als ein int ist. Int wurde als "Standard" ausgewählt, da die meisten Benutzer keine harten Codierungswerte über 2.147.483.647 oder unter -2.147.483.648 haben

0
Ross