Datentypen Sonderbehandlung primitiver Datentypen, fixe Konstanteninterpretation

Sae1962

Mitglied
Hallo allerseits!

Ich bin wohl ein etwas erfahrener Javaprogrammierer, da ich schon an die zwei Jahre in Javaprojekten involviert war. Wenn man etwas länger verwendet - und es gibt sicherlich hier Teilnehmer, die über zehn Jahre Erfahrung haben - kommen manchmal Fragen zu den Grundlagen auf.

In Java sind so wie in anderen Sprachen mathematische Operatoren definiert. Diese können auf die primitiven Datentypen
Code:
int
,
Code:
long
, und
Code:
double
angewendet werden, die ja nicht wirklich objektorientiert sind, da keine Klassen. Allerdings gibt es die arithmetischen Operation
Code:
+
,
Code:
-
,
Code:
*
, und
Code:
/
nicht wirklich für die primitiven Datentypen
Code:
byte
und
Code:
short
. So wird bei einer speichermäßig minimalistischen Anwendung ein
Java:
 byte significantsAfterDecimal = 4;
 byte significantsBeforeDecimal = 1;
 byte significants = significantsAfterDecimal - significantsBeforeDecimal;   // Fehler!

nicht akzeptiert. Dasselbe gilt für den Typ
Code:
short
. Um die Operation auszuführen, wandelt der Übersetzer die Werte in diesem Falle in ein int um. Da das Resultat wieder ein
Code:
int
ist, muss man den speichermäßig größeren Wert selbst in den erwünschten Typen zurück umwandeln, also
Java:
 byte significants = (byte)(significantsAfterDecimal - significantsBeforeDecimal);
Ähnlich gibt es "Missverständnisse" mit dem Übersetzer, wenn man
Java:
 float length = 4.3;   // Fehler!
schreibt, da blindlings die Konstante als einen
Code:
double
sieht und deshalb eine Umwandlung oder Bezeichnung notwendig ist:
Java:
 float length = 4.3f;   // an Stelle von (float)4.3;
Ähnlich ist es in C#, wo ich gerade ein Projekt abgeschlossen habe.

Frage:
Warum können oder wollen die Übersetzer nicht mit manchen primitiven Datentypen operieren? Gibt es ein "Tao" dahinter, warum der Übersetzer bzgl. Datentyp einer Konstante voreingenommen ist?

Ich suche nach konkreten Antworten, die diese auch begründen können. Vermutungen habe ich selber auch. 😀

Danke für die Auskunft!

PS: Ich habe im Web nach meiner Frage gesucht, aber nichts befriedigendes gefunden.
 
bei Ganzzahltypen klappt die Werteprüfung,
abgesehen davon dass man an einem Long-Wert immer l ranschreiben muss, ob für eine int-Variable oder long,

4.3 in einer float-Variablen gespeichert ist was anderes als 4.3 als double,
da in Binärdarstellung ähnlich zu runden ist wie 1/3 = 0.3333333 in Dezimalschreibweise,

freilich meckert der Compiler auch bei exakten Zahlen wie 4.25, so genau wird da nicht extra geprüft..

Java:
public class Test {
    public static void main(String[] args)  {
        byte b = 105;
        // byte b2 = 305; // geht nicht
        long c = 490589048590l;

        float f = 4.3f;
        double d = 4.3;
        System.out.println(d - f); // relativ große Differenz
        float f2 = 4.25f;
        double d2 = 4.25;
        System.out.println(d2 - f2); // 0
    }
}

-------

dass Java in int rechnet ist glaube ich einfacher für die maschinelle Umsetzung (int = 32bit),
als Gesetzmäßigkeit letztlich auch von Vorteil für den Programmierer, der dann weiß dass es keine byte-Überläufe usw. gibt

am Ende wieder von selber auf byte casten, zumindest wenn die Grenzen sicher erhalten bleiben,
wäre vielleicht nett, aber (jetzt eine Vermutung) könnte für den Compilier zu viel sein,
er müsste extra die beteiligten Variablen anschauen, prüfen ob sie nicht zwischendurch verändert wurden,

er müßte das Ergebnis praktisch im Voraus berechnen, also alle mathematische Funktionalität integriert haben
(Verrechnen wäre fatal, davon können Millionen abhängen, ob Geld oder Menschen)
statt einfach nur die Syntax zu prüfen und bei Rechenzeichen 'Rechnung' anzunehmen, was deutlich leichter ist

für Instanzattribute/ sonstiges hochvariables fällt die Prüfung eh aus,

als Entlastung ist anzumerken, dass der/ manche Compiler ähnliches doch schon prüft,
Unreachable Code, 'Null pointer access' in Eclipse
 
ein weiterer Spezialfall ist, was hier gerade ein Thema ist:
http://www.java-forum.org/java-basi...m-addition-geht-langform-scheitert-typen.html

Java:
int x = 4; char b = 'a';
 
b += x; // geht
b = b + x; // geht nicht
+= geht selbst mit großen Zahlen zum Überlauf, sogar mit double, da ist einfach eingebaut dass nicht geprüft wird,
während beim zweiten wieder erst eine Interpretation fällig wäre, ob es wenigstens direkt dem += entspricht
 
Danke für die Antwort!

Man könnte aber auch die "fehlenden" Operationen hinzufügen und (z.B. bei einem 32-Bit-Prozessor) gleich vier Rechnungen in einem Streich durchführen, wenn man mit
Code:
byte
rechnet. Bei
Code:
short
wären es dann zwei auf einem Schlag.

Ich finde es nur historisch interessant, dass einerseits die Prozessoren sehr wohl die Möglichkeit anbieten, dass mehrere kleinere Zahlen als die Datenbusbreite auf einmal berechnet werden können, man sich aber offensichtlich nicht die Mühe gemacht hat, dies in die Übersetzer (Java, C, C#, usw.) zu nutzen.

Ich wäre für eine Erweiterung, was auch eine Vereinheitlichung der Operationen auf primitiven Datentypen wäre. Und Ausnahmen machen das Verständnis komplizierter. Zugegeben: so eine Erweiterung müsste vorerest gründlich getestet werden - funktional, leistungsmäßig, etc. Aber sie scheint mir trotzdem gar nicht abwegig, sondern eher naheliegend.
 
Java:
public class Test {

	public static void main(String[] args) {
		new Test(1);
	}

	public Test(byte b) {
	}

}

Warum gibt er hier eigentlich folgenden Fehler:
Code:
The constructor Test(int) is undefined
? Und wie kann das umgehen außer mit einem
Code:
new Test((byte)1);
.
 
Jede Zahl die in deinem Quellcode steht ist für Java erstmal nen int. Hier müsstest du explizit casten, oder dir nen zweiten Konstruktor anlegen:

Java:
public Test(int i) {
  this((byte)i);
}
Damit versteckst du den cast dann natürlich nur und es kann zu hier zu ner Exception kommen.
 
Hat hierzu keiner weiteres Wissen?

Bei mir persönlich geht es jetzt zB schlicht darum, dass ich eine Android App entwickeln wollte und mir dachte, dass es eventuell sinnvoll wäre byte statt int zu verwenden wo es möglich und sinnvoll ist. Oder ist schon der Gedanke falsch? Wenn Java jetzt immer erst ein int annimmt und ich casten muss, dann geht mir der Effekt, dass ich eigentlich weniger Speicher reservieren will, im ersten Moment doch flöten, oder? Außerdem ist es hässlich, wenn ich in jedem Konstruktor casten muss, wundert mich, dass das nicht besser geht..
 
für lokale Variablen/ Parameter kannst du dir solche Sparversuche wohl sparen, falls du nicht per Rekursion an die Grenzen des Stacks gehen willst,
für die Heap dürften nur Instanzvariablen interessant sein und auch dann eher wenn du ein großes Array hast als einzelne Variablen,

warum es so ist, zumal
> byte b = 105;
geht, kann ich nicht sagen, aber bevor hier gar nichts steht die Vermutung äußern,
dass die Methodenbindung doch bisschen was anderes als eine einfache lokale Variablendeklaration ist,

ich nehme kühn an, dass das irgendwie in getrennten Compiler-Schritten stattfindet,
und damit ist im ersten Schritt die Wert-Typermittlung bei int zu Ende gegangen, beim zweiten dann nicht mehr zu drehen,
mit entsprechenden Aufwand sollte es wohl technisch möglich sein, aber alles hat seine Grenzen
 

Zurück
Oben