Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Exceptions
7 Äußere.innere Klassen
8 Besondere Klassen der Java SE
9 Generics<T>
10 Architektur, Design und angewandte Objektorientierung
11 Die Klassenbibliothek
12 Einführung in die nebenläufige Programmierung
13 Einführung in Datenstrukturen und Algorithmen
14 Einführung in grafische Oberflächen
15 Einführung in Dateien und Datenströme
16 Einführung in die <XML>-Verarbeitung mit Java
17 Einführung ins Datenbankmanagement mit JDBC
18 Bits und Bytes und Mathematisches
19 Die Werkzeuge des JDK
A Die Klassenbibliothek
Stichwort

Download:
- Aufgaben, ca. 1,1 MB
- Programme, ca. 12,8 MB

Buch bestellen
Ihre Meinung?

Spacer
Java ist auch eine Insel von Christian Ullenboom
Das umfassende Handbuch
Buch: Java ist auch eine Insel

Java ist auch eine Insel
Rheinwerk Computing
1308 S., 10., aktualisierte Auflage, geb., mit DVD
ca. 49,90 Euro, ISBN 978-3-8362-1802-3
Pfeil 2 Imperative Sprachkonzepte
Pfeil 2.1 Elemente der Programmiersprache Java
Pfeil 2.1.1 Token
Pfeil 2.1.2 Textkodierung durch Unicode-Zeichen
Pfeil 2.1.3 Bezeichner
Pfeil 2.1.4 Literale
Pfeil 2.1.5 Reservierte Schlüsselwörter
Pfeil 2.1.6 Zusammenfassung der lexikalischen Analyse
Pfeil 2.1.7 Kommentare
Pfeil 2.2 Von der Klasse zur Anweisung
Pfeil 2.2.1 Was sind Anweisungen?
Pfeil 2.2.2 Klassendeklaration
Pfeil 2.2.3 Die Reise beginnt am main()
Pfeil 2.2.4 Der erste Methodenaufruf: println()
Pfeil 2.2.5 Atomare Anweisungen und Anweisungssequenzen
Pfeil 2.2.6 Mehr zu print(), println() und printf() für Bildschirmausgaben
Pfeil 2.2.7 Die API-Dokumentation
Pfeil 2.2.8 Ausdrücke
Pfeil 2.2.9 Ausdrucksanweisung
Pfeil 2.2.10 Erste Idee der Objektorientierung
Pfeil 2.2.11 Modifizierer
Pfeil 2.2.12 Gruppieren von Anweisungen mit Blöcken
Pfeil 2.3 Datentypen, Typisierung, Variablen und Zuweisungen
Pfeil 2.3.1 Primitive Datentypen im Überblick
Pfeil 2.3.2 Variablendeklarationen
Pfeil 2.3.3 Konsoleneingaben
Pfeil 2.3.4 Fließkommazahlen mit den Datentypen float und double
Pfeil 2.3.5 Ganzzahlige Datentypen
Pfeil 2.3.6 Wahrheitswerte
Pfeil 2.3.7 Unterstriche in Zahlen *
Pfeil 2.3.8 Alphanumerische Zeichen
Pfeil 2.3.9 Gute Namen, schlechte Namen
Pfeil 2.3.10 Initialisierung von lokalen Variablen
Pfeil 2.4 Ausdrücke, Operanden und Operatoren
Pfeil 2.4.1 Zuweisungsoperator
Pfeil 2.4.2 Arithmetische Operatoren
Pfeil 2.4.3 Unäres Minus und Plus
Pfeil 2.4.4 Zuweisung mit Operation
Pfeil 2.4.5 Präfix- oder Postfix-Inkrement und -Dekrement
Pfeil 2.4.6 Die relationalen Operatoren und die Gleichheitsoperatoren
Pfeil 2.4.7 Logische Operatoren: Nicht, Und, Oder, Xor
Pfeil 2.4.8 Kurzschluss-Operatoren
Pfeil 2.4.9 Der Rang der Operatoren in der Auswertungsreihenfolge
Pfeil 2.4.10 Die Typanpassung (das Casting)
Pfeil 2.4.11 Überladenes Plus für Strings
Pfeil 2.4.12 Operator vermisst *
Pfeil 2.5 Bedingte Anweisungen oder Fallunterscheidungen
Pfeil 2.5.1 Die if-Anweisung
Pfeil 2.5.2 Die Alternative mit einer if-else-Anweisung wählen
Pfeil 2.5.3 Der Bedingungsoperator
Pfeil 2.5.4 Die switch-Anweisung bietet die Alternative
Pfeil 2.6 Schleifen
Pfeil 2.6.1 Die while-Schleife
Pfeil 2.6.2 Die do-while-Schleife
Pfeil 2.6.3 Die for-Schleife
Pfeil 2.6.4 Schleifenbedingungen und Vergleiche mit ==
Pfeil 2.6.5 Ausbruch planen mit break und Wiedereinstieg mit continue
Pfeil 2.6.6 break und continue mit Marken *
Pfeil 2.7 Methoden einer Klasse
Pfeil 2.7.1 Bestandteil einer Methode
Pfeil 2.7.2 Signatur-Beschreibung in der Java-API
Pfeil 2.7.3 Aufruf einer Methode
Pfeil 2.7.4 Methoden ohne Parameter deklarieren
Pfeil 2.7.5 Statische Methoden (Klassenmethoden)
Pfeil 2.7.6 Parameter, Argument und Wertübergabe
Pfeil 2.7.7 Methoden vorzeitig mit return beenden
Pfeil 2.7.8 Nicht erreichbarer Quellcode bei Methoden *
Pfeil 2.7.9 Methoden mit Rückgaben
Pfeil 2.7.10 Methoden überladen
Pfeil 2.7.11 Sichtbarkeit und Gültigkeitsbereich
Pfeil 2.7.12 Vorgegebener Wert für nicht aufgeführte Argumente *
Pfeil 2.7.13 Finale lokale Variablen
Pfeil 2.7.14 Rekursive Methoden *
Pfeil 2.7.15 Die Türme von Hanoi *
Pfeil 2.8 Zum Weiterlesen

Rheinwerk Computing - Zum Seitenanfang

2.3 Datentypen, Typisierung, Variablen und ZuweisungenZur nächsten Überschrift

Java nutzt, wie es für imperative Programmiersprachen typisch ist, Variablen zum Ablegen von Daten. Eine Variable ist ein reservierter Speicherbereich und belegt – abhängig vom Inhalt – eine feste Anzahl von Bytes. Alle Variablen (und auch Ausdrücke) haben einen Typ, der zur Übersetzungszeit bekannt ist. Der Typ wird auch Datentyp genannt, da eine Variable einen Datenwert, auch Datum genannt, enthält. Beispiele für einfache Datentypen sind: Ganzzahlen, Fließkommazahlen, Wahrheitswerte und Zeichen. Der Typ bestimmt auch die zulässigen Operationen, denn Wahrheitswerte lassen sich nicht addieren, Ganzzahlen schon. Dagegen lassen sich Fließkommazahlen addieren, aber nicht Xor-verknüpfen. Da jede Variable einen vom Programmierer vorgegebenen festen Datentyp hat, der zur Übersetzungszeit bekannt ist und sich später nicht mehr ändern lässt, und Java stark darauf achtet, welche Operationen erlaubt sind, und auch von jedem Ausdruck spätestens zur Laufzeit den Typ kennt, ist Java eine statisch typisierte und streng (stark) typisierte Programmiersprache.[58](Während in der Literatur bei den Begriffen statisch getypt und dynamisch getypt mehr oder weniger Einigkeit herrscht, haben verschiedene Autoren unterschiedliche Vorstellungen von den Begriffen streng (stark) typisiert und schwach typisiert.)

Hinweis

In Java muss der Datentyp einer Variablen zur Übersetzungszeit bekannt sein. Das nennt sich dann statisch typisiert. Das Gegenteil ist eine dynamische Typisierung, wie sie etwa JavaScript verwendet. Hier kann sich der Typ einer Variablen zur Laufzeit ändern, je nachdem, was die Variable enthält.

Primitiv- oder Verweis-Typ

Die Datentypen in Java zerfallen in zwei Kategorien:

  • Primitive Typen: Die primitiven (einfachen) Typen sind die eingebauten Datentypen für Zahlen, Unicode-Zeichen und Wahrheitswerte.
  • Referenztypen: Mit diesem Datentyp lassen sich Objektverweise etwa auf Zeichenketten, Dialoge oder Datenstrukturen verwalten.

Warum sich damals Sun für diese Teilung entschieden hat, lässt sich mit zwei Gründen erklären:

  • Zu der Zeit, als Java eingeführt wurde, kannten viele Programmierer die Syntax und Semantik von C(++) und ähnlichen imperativen Programmiersprachen. Zur neuen Sprache Java zu wechseln, fiel dadurch leichter, und es half, sich sofort auf der Insel zurechtzufinden. Es gibt aber auch Programmiersprachen wie Smalltalk, die keine primitiven Datentypen besitzen.
  • Der andere Grund ist die Tatsache, dass häufig vorkommende elementare Rechenoperationen schnell durchgeführt werden müssen und bei einem einfachen Typ leicht Optimierungen durchzuführen sind.

Wir werden uns im Folgenden erst mit primitiven Datentypen beschäftigen. Referenzen werden nur dann eingesetzt, wenn Objekte ins Spiel kommen. Die nehmen wir uns in Kapitel 3, »Klassen und Objekte«, vor.


Rheinwerk Computing - Zum Seitenanfang

2.3.1 Primitive Datentypen im ÜberblickZur nächsten ÜberschriftZur vorigen Überschrift

In Java gibt es zwei Arten eingebauter Datentypen:

  • arithmetische Typen (ganze Zahlen – auch integrale Typen genannt –, Fließkommazahlen, Unicode-Zeichen)
  • Wahrheitswerte für die Zustände wahr und falsch

Die folgende Tabelle vermittelt dazu einen Überblick. Anschließend betrachten wir jeden Datentyp präziser.

Tabelle 2.5: Java-Datentypen und ihre Wertebereiche

Typ Belegung (Wertebereich)
boolean true oder false
char 16-Bit-Unicode-Zeichen (0x0000 ... 0xFFFF)
byte –2^7 bis 2^7 – 1 (–128 ... 127)
short –2^15 bis 2^15 – 1 (–32.768 ... 32.767)
int –2^31 bis 2^31 – 1 (–2.147.483.648 ... 2.147.483.647)
long –2^63 bis 2^63 – 1 (–9.223.372.036.854.775.808 ... 9.223.372.036.854.775.807)
float 1,40239846E-45f ... 3,40282347E+38f
double 4,94065645841246544E-324 ... 1,79769131486231570E+308

Bei den Ganzzahlen fällt auf, dass es eine positive Zahl »weniger« gibt als negative.

Für float und double ist das Vorzeichen nicht angegeben, da die kleinsten und größten darstellbaren Zahlen sowohl positiv wie auch negativ sein können. Mit anderen Worten: Die Wertebereiche unterscheiden sich nicht – anders als etwa bei int – in Abhängigkeit vom Vorzeichen. Wer eine »klassische« Darstellung wünscht, der kann sich das so vorstellen: Der Wertebereich (vom double) ist 4,94065645841246544E-324 bis 1,79769131486231570E+308 bzw. mit dem Vorzeichen von etwa –1.8E308 (über –4,9E-324 und +4,9E-324) bis +1.8E308.[59](Es gibt bei Fließkommazahlen noch »Sonderzahlen«, wie plus oder minus Unendlich, aber dazu später mehr.)

Detailwissen

Genau genommen sieht die Sprachgrammatik von Java keine negativen Zahlenliterale vor. Bei einer Zahl wie –1.2 oder –1 ist das Minus der unäre Operator und gehört nicht zur Zahl. Im Bytecode selbst sind die negativen Zahlen natürlich wieder abgebildet.

Abbildung

Die folgende Tabelle zeigt eine etwas andere Darstellung:

Tabelle 2.6: Java-Datentypen und ihre Größen und Formate

Typ Größe Format
Ganzzahlen
byte 8 Bit Zweierkomplement
short 16 Bit Zweierkomplement
int 32 Bit Zweierkomplement
long 64 Bit Zweierkomplement
Fließkommazahlen
float 32 Bit IEEE 754
double 64 Bit IEEE 754
Weitere Datentypen
boolean 1 Bit true, false
char 16 Bit 16-Bit-Unicode
Hinweis

Strings werden bevorzugt behandelt, sind aber lediglich Verweise auf Objekte und kein primitiver Datentyp.

Zwei wesentliche Punkte zeichnen die primitiven Datentypen aus:

  • Alle Datentypen haben eine festgesetzte Länge, die sich unter keinen Umständen ändert. Der Nachteil, dass sich bei einigen Hochsprachen die Länge eines Datentyps ändern kann, besteht in Java nicht. In den Sprachen C(++) bleibt dies immer unsicher, und die Umstellung auf 64-Bit-Maschinen bringt viele Probleme mit sich. Der Datentyp char ist 16 Bit lang.
  • Die numerischen Datentypen byte, short, int und long sind vorzeichenbehaftet, Fließkommazahlen sowieso. Dies ist leider nicht immer praktisch, aber wir müssen stets daran denken. Probleme gibt es, wenn wir einem Byte zum Beispiel den Wert 240 zuweisen wollen, denn 240 liegt außerhalb des Wertebereichs, der von –128 bis 127 reicht. Ein char ist im Prinzip ein vorzeichenloser Ganzzahltyp.

Wenn wir also die numerischen Datentypen (lassen wir hier char außen vor) nach ihrer Größe sortieren wollten, könnten wir zwei Linien für Ganzzahlen und Fließkommazahlen aufbauen:

byte < short < int < long
float < double
Hinweis

Die Klassen Byte, Integer, Long, Short, Character, Double und Float deklarieren die Konstanten MAX_VALUE und MIN_VALUE, die den größten und kleinsten zulässigen Wert des jeweiligen Wertebereichs bzw. die Grenzen der Wertebereiche der jeweiligen Datentypen angeben.

System.out.println( Byte.MIN_VALUE );       // –128
System.out.println( Byte.MAX_VALUE ); // 127
System.out.println( Character.MIN_VALUE ); // '\u0000'
System.out.println( Character.MAX_VALUE ); // '\uFFFF'
System.out.println( Double.MIN_VALUE ); // 4.9E-324
System.out.println( Double.MAX_VALUE ); // 1.7976931348623157E308


Rheinwerk Computing - Zum Seitenanfang

2.3.2 VariablendeklarationenZur nächsten ÜberschriftZur vorigen Überschrift

Mit Variablen lassen sich Daten speichern, die vom Programm gelesen und geschrieben werden können. Um Variablen zu nutzen, müssen sie deklariert (definiert[60](In C(++) bedeuten Definition und Deklaration etwas Verschiedenes. In Java kennen wir diesen Unterschied nicht und betrachten daher beide Begriffe als gleichwertig. Die Spezifikation spricht nur von Deklarationen.)) werden. Die Schreibweise einer Variablendeklaration ist immer die gleiche: Hinter dem Typnamen folgt der Name der Variablen. Sie ist eine Anweisung und wird daher mit einem Semikolon abgeschlossen. In Java kennt der Compiler von jeder Variablen und jedem Ausdruck genau den Typ.

Deklarieren wir ein paar (lokale) Variablen in der main()-Methode:

Listing 2.5: FirstVariable.java

public class FirstVariable
{
public static void main( String[] args )
{
String name; // Name
int age; // Alter
double income; // Einkommen
char gender; // Geschlecht ('f' oder 'm')
boolean isPresident; // Ist Präsident (true oder false)
boolean isVegetarian; // Ist die Person Vegetarier?
}
}

Der Typname ist entweder ein einfacher Typ (wie int) oder ein Referenztyp. Viel schwieriger ist eine Deklaration nicht – kryptische Angaben wie in C gibt es in Java nicht.[61](Das ist natürlich eine Anspielung auf C, in dem Deklarationen wie char (*(*a[2])())[2] möglich sind. Gut, dass es mit cdecl ein Programm zum »Vorlesen« solcher Definitionen gibt.) Ein Variablenname (der dann Bezeichner ist) kann alle Buchstaben und Ziffern des Unicode-Zeichensatzes beinhalten, mit der Ausnahme, dass am Anfang des Bezeichners keine Ziffer stehen darf. Auch darf der Bezeichnername mit keinem reservierten Schlüsselwort identisch sein.

Mehrere Variablen kompakt deklarieren

Im oberen Beispiel sind zwei Variaben vom gleichen Typ: isPresident und isVegetarian.

boolean isPresident;
boolean isVegetarian;

Immer dann, wenn der Variablentyp der gleiche ist, lässt sich die Deklaration verkürzen: Variablen werden mit Komma getrennt.

boolean isPresident, isVegetarian;

Variablendeklaration mit Wertinitialisierung

Gleich bei der Deklaration lassen sich Variablen mit einem Anfangswert initialisieren. Hinter einem Gleichheitszeichen steht der Wert, der oft ein Literal ist. Ein Beispielprogramm:

Listing 2.6: Obama.java

public class Obama
{
public static void main( String[] args )
{
String name = "Barack Hussein Obama II";
int age = 48;
double income = 400000;
char gender = 'm';
boolean isPresident = true;

}
}

Wir haben gesehen, dass bei der Deklaration mehrerer Variablen gleichen Typs ein Komma die Bezeichner trennt. Das überträgt sich auch auf die Initialisierung. Ein Beispiel:

boolean sendSms = true,
bungaBungaParty = true;
String person1 = "Silvio", person2 = "Ruby the Heart Stealer";
double x, y, bodyHeight = 183;

Die Zeilen deklarieren mehrere Variablen auf einen Schlag. x und y am Schluss bleiben uninitialisiert.

Zinsen berechnen als Beispiel zur Variablendeklaration, -initialisierung & -ausgabe

Zusammen mit der Konsoleneingabe können wir schon einen einfachen Zinsrechner programmieren. Er soll uns ausgeben, wie hoch die Zinsen für ein gegebenes Kapital bei einem gegebenen Zinssatz (engl. interest rate) nach einer gewissen Zeit sind.

Listing 2.7: InterestRates.java

public class InterestRates
{
public static void main( String[] args )
{
double capital = 20000 /* Euro */;
double interestRate = 3.6 /* Prozent */;
double years = 2;

double interestRates = capital * interestRate * years / 100;
System.out.printf( "Zinsen: " + interestRates ); // 1440.0
}
}

Das obige Beispiel macht ebenfalls deutlich, dass Strings mit dem Plus aneinandergehängt werden können; ist ein Teil kein String, so wird er in einen String konvertiert.


Rheinwerk Computing - Zum Seitenanfang

2.3.3 KonsoleneingabenZur nächsten ÜberschriftZur vorigen Überschrift

Bisher haben wir zwei Methoden kennengelernt: println() und random(). Die Methode println() »hängt« am System.out bzw. System.err-Objekt und random() »hängt« am Math-Objekt.

Der Gegenpol zu println() ist eine Konsoleneingabe. Hier gibt es unterschiedliche Varianten. Die einfachste ist mit der Klasse java.util.Scanner. In Kapitel 4, »Der Umgang mit Zeichenketten«, wird die Klasse noch viel genauer untersucht. Es reicht aber an dieser Stelle zu wissen, wie Strings, Ganzzahlen und Fließkommazahlen eingelesen werden.

Tabelle 2.7: Einlesen einer Zeichenkette, Ganz- und Fließkommazahl von der Konsole

Eingabe lesen vom Typ Anweisung
String String s = new java.util.Scanner(System.in).nextLine();
int int i = new java.util.Scanner(System.in).nextInt();
double double d = new java.util.Scanner(System.in).nextDouble();

Verbinden wir die drei Möglichkeiten zu einem Beispiel. Zunächst soll der Name eingelesen werden, dann das Alter und anschließend eine Fließkommazahl.

Listing 2.8: SmallConversation.java

public class SmallConversation
{
public static void main( String[] args )
{
System.out.println( "Moin! Wie heißt denn du?" );
String name = new java.util.Scanner( System.in ).nextLine();
System.out.printf( "Hallo %s. Wie alt bist du?%n", name );
int age = new java.util.Scanner( System.in ).nextInt();
System.out.printf( "Aha, %s Jahre, das ist ja die Hälfte von %s.%n",
age, age * 2 );
System.out.println( "Sag mal, was ist deine Lieblingsfließkommazahl?" );
double value = new java.util.Scanner( System.in ).nextDouble();
System.out.printf( "%s? Aha, meine ist %s.%n",
value, Math.random() * 100000 );
}
}

Eine Konversation sieht somit etwa so aus:

Moin! Wie heißt denn du?
Christian

Hallo Christian. Wie alt bist du?
37

Aha, 37 Jahre, das ist ja die Hälfte von 74.
Sag mal, was ist deine Lieblingsfließkommazahl?
9,7

9.7? Aha, meine ist 60769.81705995359.

Die Eingabe der Fließkommazahl muss mit Komma erfolgen, wenn die JVM auf einem deutschsprachigen Betriebssystem läuft. Die Ausgabe über printf() kann ebenfalls lokalisierte Fließkommazahlen schreiben, dann muss jedoch statt dem Platzhalter %s die Kennung %f oder %g verwendet werden. Das wollen wir in einem zweiten Beispiel nutzen.

Zinsberechnung mit der Benutzereingabe

Die Zinsberechnung, die vorher feste Werte im Programm hatte, soll eine Benutzereingabe bekommen. Des Weiteren erwarteten wir die Dauer in Monaten statt Jahren.

Listing 2.9: MyInterestRates.java

public class MyInterestRates
{
public static void main( String[] args )
{
System.out.println( "Kapital?" );
double capital = new java.util.Scanner( System.in ).nextDouble();

System.out.println( "Zinssatz?" );
double interestRate = new java.util.Scanner( System.in ).nextDouble();

System.out.println( "Anlagedauer in Monaten?" );
int month = new java.util.Scanner( System.in ).nextInt();

double interestRates = capital * interestRate * month / (12*100);
System.out.printf( "Zinsen: %g%n", interestRates );
}
}

Die vorher fest verdrahteten Werte sind nun alle dynamisch, und wir kommen mit den Eingaben zum gleichen Ergebnis wir vorher:

Kapital?
20000

Zinssatz?
3,6

Anlagedauer in Monaten?
24

Zinsen: 1440,00

Rheinwerk Computing - Zum Seitenanfang

2.3.4 Fließkommazahlen mit den Datentypen float und doubleZur nächsten ÜberschriftZur vorigen Überschrift

Für Fließkommazahlen (auch Gleitkommazahlen genannt) einfacher und erhöhter Genauigkeit bietet Java die Datentypen float und double. Die Datentypen sind im IEEE 754-Standard beschrieben und haben eine Länge von 4 Byte für float und 8 Byte für double. Fließkommaliterale können einen Vorkommateil und einen Nachkommateil besitzen, die durch einen Dezimalpunkt (kein Komma) getrennt sind. Ein Fließkommaliteral muss keine Vor- oder Nachkommastellen besitzen, sodass auch Folgendes gültig ist:

double d = 10.0 + 20. + .11;
Hinweis

Der Datentyp float ist mit 4 Byte, also 32 Bit, ein schlechter Scherz. Der Datentyp double geht mit 64 Bit ja gerade noch, wobei in Hardware eigentlich 80 Bit üblich sind.

Der Datentyp float *

Standardmäßig sind die Fließkomma-Literale vom Typ double. Ein nachgestelltes »f« (oder »F«) zeigt an, dass es sich um ein float handelt.

Beispiel

Gültige Zuweisungen für Fließkommazahlen vom Typ double und float:

double pi = 3.1415, delta = .001;
float ratio = 4.33F;

Auch für den Datentyp double lässt sich ein »d« (oder »D«) nachstellen, was allerdings nicht nötig ist, wenn Literale für Kommazahlen im Quellcode stehen; Zahlen wie 3.1415 sind automatisch vom Typ double. Während jedoch bei 1 + 2 + 4.0 erst 1 und 2 als int addiert werden, dann in double und anschließend auf 4.0 addiert werden, würde 1D + 2 + 4.0 gleich mit der Fließkommazahl 1 beginnen. So ist auch 1D gleich 1. bzw. 1.0.

Frage

Was ist das Ergebnis der Ausgabe?

System.out.println( 20000000000F == 20000000000F+1 );
System.out.println( 20000000000D == 20000000000D+1 );
Tipp: Was sind die Wertebereiche von float und double?

Noch genauere Auflösung bei Fließkommazahlen *

Einen höher auflösenden beziehungsweise präziseren Datentyp für Fließkommazahlen als double gibt es nicht. Die Standardbibliothek bietet für diese Aufgabe in java.math die Klasse BigDecimal an, die in Kapitel 18, »Bits und Bytes und Mathematisches«, näher beschrieben ist. Das ist sinnvoll für Daten, die eine sehr gute Genauigkeit aufweisen sollen, wie zum Beispiel Währungen.[62](Einige Programmiersprachen besitzen für Währungen eingebaute Datentypen, wie LotusScript mit Currency, das mit 8 Byte einen sehr großen und genauen Wertebereich abdeckt. Erstaunlicherweise gab es einmal in C# den Datentyp currency für ganzzahlige Währungen.)

Sprachvergleich

In C# gibt es den Datentyp decimal, der mit 128 Bit (also 16 Byte) auch genügend Präzision bietet, um eine Zahl wie 0,000000000000000000000000001 auszudrücken.


Rheinwerk Computing - Zum Seitenanfang

2.3.5 Ganzzahlige DatentypenZur nächsten ÜberschriftZur vorigen Überschrift

Java stellt fünf ganzzahlige Datentypen zur Verfügung: byte, short, char, int und long. Die feste Länge von jeweils 1, 2, 2, 4 und 8 Byte ist eine wesentliche Eigenschaft von Java. Ganzzahlige Typen sind in Java immer vorzeichenbehaftet (mit der Ausnahme von char); einen Modifizierer unsigned wie in C(++) gibt es nicht.[63](In Java bilden long und short einen eigenen Datentyp. Sie dienen nicht wie in C(++) als Modifizierer. Eine Deklaration wie long int i ist also genauso falsch wie long long time_ago.) Negative Zahlen werden durch Voranstellen eines Minuszeichens gebildet. Ein Pluszeichen für positive Zeichen ist möglich. int und long sind die bevorzugten Typen. byte kommt selten vor und short nur in wirklich sehr seltenen Fällen, etwa bei Feldern mit Bilddaten.

Ganzzahlen sind standardmäßig vom Typ int

Betrachten wir folgende Zeile, so ist auf den ersten Blick kein Fehler zu erkennen:

System.out.println( 123456789012345 );      // Fehler

Dennoch übersetzt der Compiler die Zeile nicht, da er ein Ganzzahlliteral ohne explizite Größenangabe als 32 Bit langes int annimmt. Die obige Zeile führt daher zu einem Compilerfehler, da unsere Zahl nicht im Wertebereich von –2.147.483.648 ... +2.147.483.647 liegt, sondern weit außerhalb: 2147483647 < 123456789012345. Java reserviert also nicht so viele Bits wie benötigt und wählt nicht automatisch den passenden Wertebereich.

Wer wird mehrfacher Milliardär? Der Datentyp long

Der Compiler betrachtet jede Ganzzahl automatisch als int. Sollte der Wertebereich von etwa plus/minus zwei Milliarden nicht reichen, greifen Entwickler zum nächsthöheren Datentyp. Dass eine Zahl long ist, muss ausdrücklich angegeben werden. Dazu wird an das Ende von Ganzzahlliteralen vom Typ long ein »l« oder »L« gesetzt. Um die Zahl 123456789012345 gültig ausgeben zu lassen, ist Folgendes zu schreiben:

System.out.println( 123456789012345L );
Tipp

Das kleine »l« hat sehr viel Ähnlichkeit mit der Ziffer Eins. Daher sollte bei Längenangaben immer ein großes »L« eingefügt werden.


Frage

Was gibt die folgende Anweisung aus?

System.out.println( 123456789 + 5432l );

Der Datentyp byte

Ein byte ist ein Datentyp mit einem Wertebereich von –128 bis +127. Eine Initialisierung wie

byte b = 200;      // Fehler

ist also nicht erlaubt, da 200 > 127 ist. Somit fallen alle Zahlen von 128 bis 255 (hexadezimal 8016 – FF16) raus. In der Datenverarbeitung ist das Java-byte, weil es ein Vorzeichen trägt, nur mittelprächtig brauchbar, da insbesondere in der Dateiverarbeitung Wertebereiche von 0 bis 255 gewünscht sind.

Java erlaubt zwar keine vorzeichenlosen Ganzzahlen, aber mit zwei Schreibweisen lassen sich doch Zahlen wie 200 in einem byte speichern.

byte b = (byte) 200;

Der Java-Compiler nimmt dazu einfach die Bitbelegung von 200 und interpretiert das oberste dann gesetzte Bit als Vorzeichenbit. Bei der Ausgabe fällt das auf:

byte b = (byte) 200;
System.out.println( b ); // –56

Der Datentyp short *

Der Datentyp short ist selten anzutreffen. Mit seinen 2 Byte kann er einen Wertebereich von –32.768 bis +32.767 darstellen. Das Vorzeichen »kostet« wie bei den anderen Ganzzahlen 1 Bit, sodass nicht 16 Bit, sondern nur 15 Bit für Zahlen zu Verfügung stehen. Allerdings gilt wie beim byte, dass auch ein short ohne Vorzeichen auf zwei Arten initialisiert werden kann:

short s = (short) 33000;
System.out.println( s ); // –32536

Rheinwerk Computing - Zum Seitenanfang

2.3.6 WahrheitswerteZur nächsten ÜberschriftZur vorigen Überschrift

Der Datentyp boolean beschreibt einen Wahrheitswert, der entweder true oder false ist. Die Zeichenketten true und false sind reservierte Wörter und bilden neben konstanten Strings und primitiven Datentypen Literale. Kein anderer Wert ist für Wahrheitswerte möglich, insbesondere werden numerische Werte nicht als Wahrheitswerte interpretiert.

Der boolesche Typ wird beispielsweise bei Bedingungen, Verzweigungen oder Schleifen benötigt. In der Regel ergibt sich ein Wahrheitswert aus Vergleichen.


Rheinwerk Computing - Zum Seitenanfang

2.3.7 Unterstriche in Zahlen *Zur nächsten ÜberschriftZur vorigen Überschrift

Um eine Anzahl von Millisekunden in Tage zu konvertieren, muss einfach eine Division vorgenommen werden. Um Millisekunden in Sekunden umzurechnen, brauchen wir eine Division durch 1000, von Sekunden auf Minuten eine Division durch 60, von Minuten auf Stunden eine Division durch 60, und die Stunden auf Tage bringt die letzte Division durch 24. Schreiben wir das auf:

long millis = 10 * 24*60*60*1000L;
long days = millis / 86400000L;
System.out.println( days ); // 10

Eine Sache fällt bei der Zahl 86400000 auf: Besonders gut lesbar ist sie nicht. Die eine Lösung ist, es erst gar nicht zu so einer Zahl kommen zu lassen und sie wie in der ersten Zeile durch eine Reihe von Multiplikationen aufzubauen – mehr Laufzeit kostet das nicht, da dieser konstante Ausdruck zur Übersetzungszeit feststeht.

Die zweite Variante ist eine neue Schreibweise, die Java 7 einführt: Unterstriche in Zahlen. Anstatt ein numerisches Literal als 86400000 zu schreiben, ist in Java 7 auch Folgendes erlaubt:

long millis = 10 * 86_400_000L;
long days = millis / 86_400_000L;
System.out.println( days ); // 10

Die Unterstriche machen die 1000er-Blöcke gut sichtbar. Hilfreich ist die Schreibweise auch bei Literalen in Binär- und Hexdarstellung, da die Unterstriche hier ebenfalls Blöcke absetzen können.[64](Bei Umrechnungen zwischen Stunden, Minuten und so weiter hilft auch die Klasse TimeUnit mit einigen statischen toXXX()-Methoden.)

Beispiel

Unterstriche verdeutlichen Blöcke bei Binär- und Hexadezimalzahlen.

int  i = 0b01101001_01001101_11100101_01011110;
long l = 0x7fff_ffff_ffff_ffffL;

Der Unterstrich darf in jedem Literal stehen, zwei aufeinanderfolgende Unterstriche sind aber nicht erlaubt.


Rheinwerk Computing - Zum Seitenanfang

2.3.8 Alphanumerische ZeichenZur nächsten ÜberschriftZur vorigen Überschrift

Der alphanumerische Datentyp char (von engl. character, Zeichen) ist 2 Byte groß und nimmt ein Unicode-Zeichen auf. Ein char ist nicht vorzeichenbehaftet. Die Literale für Zeichen werden in einfache Hochkommata gesetzt. Spracheinsteiger verwechseln häufig die einfachen Hochkommata mit den Anführungszeichen der Zeichenketten (Strings). Die einfache Merkregel lautet: ein Zeichen – ein Hochkomma, mehrere Zeichen – zwei Hochkommata (Gänsefüßchen).

Beispiel

Korrekte Hochkommata für Zeichen und Zeichenketten:

char   c = 'a';
String s = "Heut' schon gebeckert?";

Da der Compiler ein char automatisch in ein int konvertieren kann, ist auch int c = 'a'; gültig.


Rheinwerk Computing - Zum Seitenanfang

2.3.9 Gute Namen, schlechte NamenZur nächsten ÜberschriftZur vorigen Überschrift

Für die optimale Lesbarkeit und Verständlichkeit eines Programmcodes sollten Entwickler beim Schreiben einige Punkte berücksichtigen:

  • Ein konsistentes Namensschema ist wichtig. Heißt ein Zähler no, nr, cnr oder counter? Auch sollten wir korrekt schreiben und auf Rechtschreibfehler achten, denn leicht wird aus necessaryConnection dann nesesarryConnection. Variablen ähnlicher Schreibweise, etwa counter und counters, sind zu vermeiden.
  • Abstrakte Bezeichner sind ebenfalls zu vermeiden. Die Deklaration int TEN = 10; ist absurd. Eine unsinnige Idee ist auch die folgende: boolean FALSE = true, TRUE = false;. Im Programmcode würde dann mit FALSE und TRUE gearbeitet. Einer der obersten Plätze bei einem Wettbewerb für die verpfuschtesten Java-Programme wäre uns gewiss.
  • Unicode-Sequenzen können zwar in Bezeichnern aufgenommen werden, doch sollten sie vermieden werden. In double übelkübel, \u00FCbelk\u00FCbel; sind beide Bezeichnernamen gleich, und der Compiler meldet einen Fehler.
  • 0 und O und 1 und l sind leicht zu verwechseln. Die Kombination »rn« ist schwer zu lesen und je nach Zeichensatz leicht mit »m« zu verwechseln.[65](Eine Software wie Mathematica warnt vor Variablen mit fast identischem Namen.) Gültig – aber böse – ist auch: int ínt, ìnt, înt; boolean bôõleañ;
Bemerkung

In China gibt es 90 Millionen Familien mit dem Nachnamen Li. Das wäre so, als ob wir jede Variable temp1, temp2 ... nennen würden.

Abbildung
Ist ein Bezeichnername unglücklich gewählt (pneumonoultramicroscopicsilicovolcano coniosis ist schon etwas lang), so lässt er sich problemlos konsistent umbenennen. Dazu wählen wir im Menü Refactor • Rename – oder auch kurz Alt + ª + R; der Cursor muss auf dem Bezeichner stehen. Eine optionale Vorschau (engl. preview) zeigt an, welche Änderungen die Umbenennung nach sich ziehen wird. Neben Rename gibt es auch noch eine andere Möglichkeit. Dazu lässt sich auf der Variablen mit Strg + 1 ein Popup-Fenster mit Local Rename öffnen. Der Bezeichner wird selektiert und lässt sich ändern. Gleichzeitig ändern sich alle Bezüge auf die Variable mit.


Rheinwerk Computing - Zum Seitenanfang

2.3.10 Initialisierung von lokalen VariablenZur vorigen Überschrift

Die Laufzeitumgebung – beziehungsweise der Compiler – initialisiert lokale Variablen nicht automatisch mit einem Nullwert bzw. Wahrheitsvarianten nicht mit false. Vor dem Lesen müssen lokale Variablen von Hand initialisiert werden, anderfalls gibt der Compiler eine Fehlermeldung aus.[66](Anders ist das bei Objektvariablen (und statischen Variablen sowie Feldern). Sie sind standardmäßig mit null (Referenzen), 0 (bei Zahlen) oder false belegt.)

Im folgenden Beispiel seien die beiden lokalen Variablen age und adult nicht automatisch initialisiert, und so kommt es bei der versuchten Ausgabe von age zu einem Compilerfehler. Der Grund ist, dass ein Lesezugriff nötig ist, aber vorher noch kein Schreibzugriff stattfand.

int     age;
boolean adult;
System.out.println( age ); // Fehler Local variable age may not have been initialized.
age = 18;
if ( age >= 18 ) // Fallunterscheidung: wenn-dann
adult = true;
System.out.println( adult ); // Fehler Local variable adult may not have been initialized.

Weil Zuweisungen in bedingten Anweisungen vielleicht nicht ausgeführt werden, meldet der Compiler auch bei System.out.println(adult) einen Fehler, da er analysiert, dass es einen Programmfluss ohne die Zuweisung gibt. Da adult nur nach der if-Abfrage auf den Wert true gesetzt wird, wäre nur unter der Bedingung, dass age größer gleich 18 ist, ein Schreibzugriff auf adult erfolgt und ein folgender Lesezugriff möglich. Doch da der Compiler annimmt, dass es andere Fälle geben kann, wäre ein Zugriff auf eine nicht initialisierte Variable ein Fehler.

Abbildung
Eclipse zeigt einen Hinweis und einen Verbesserungsvorschlag an, wenn eine lokale Variable nicht initialisiert ist.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Java SE Bibliotheken






 Java SE Bibliotheken


Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Einstieg in Eclipse






 Einstieg in
 Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in
 Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2011
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de