Kapitel 1 Grundlagen
Nach einem Überblick über die »etwas andere« Java-Technologie werden die Details zu den grundlegenden Bausteinen in möglichst einfachen Regeln zusammengefasst.
Konventionen und Stile sind grundlegende Bausteine einer Sprache, also schließt das Kapitel mit Namenskonventionen ab.
Die Zusammenstellung dieser Grundlagen orientiert sich an den Anforderungen der Zertifizierung (siehe Vorwort) und hebt dabei besonders die Aspekte hervor, die Java von C/C++ unterscheiden.
Damit ein weitgehend goto-freies Lesen möglich ist, werden verwendete Begriffe wie Interface, Ausnahmen, Array etc. kurz vorgestellt, obwohl sie erst in späteren Kapiteln ausführlich behandelt werden.1
Testfragen am Ende des Kapitels
Anhand der abschließenden Fragen kann geprüft werden, ob das Basiswissen für einfache Zertifizierungsfragen ausreicht, und ggf. sollte der zugehörige Abschnitt nachgearbeitet werden.
1.1 Java-Überblick ![down](common/down.gif) ![top](common/15x15leer.gif)
Java-Technologie: Sprache, Plattform, JVM
Das Wort Java steht für eine Technologie, die drei zentrale Komponenten umfasst:
|
die eigentliche Java-Programmiersprache, die Syntax und Semantik festlegt. |
|
die Java-Plattform, kurz J2SE (Java 2 Standard Edition), die auf Basis der Programmiersprache ein umfassendes Klassensystem bereitstellt, um Java-Anwendungen unabhängig vom API2 des Betriebssystems zu programmieren. |
|
die Java Virtual Maschine (JVM), die Java-Code von der realen Maschine unabhängig macht, d.h. den Java-Byte-Code ausführt. Vom Betriebssystem bleibt die JVM natürlich abhängig. |
Die Java-Sprache selbst ist seit der Einführung 1995 bemerkenswert stabil. Aufgrund der Erfahrungen mit C/C++, Smalltalk und Oberon war das Design bereits so ausgereift, dass die Sprache nachfolgend kaum geändert wurde, was man allerdings von den beiden anderen Komponenten (Plattform, JVM) nicht unbedingt behaupten kann.
Die Evolution der Java-Plattform
deprecated
Obwohl die Sprache die Basis darstellt, liegt die Funktionalität von Java in der Plattform. Sie hat bis zur Version 1.3 gewaltige Änderungen bzw. Erweiterungen erfahren, die zum Teil nur mühsam in das vorherige Klassensystem eingepasst werden konnten. Die Warnung deprecated3 und konkurrierende Funktionalitäten in alten und neuen Klassen belegen dies.
Aufgrund der umfangreichen Änderungen wurde ab der Plattformversion 1.2 die offizielle Bezeichnung Java 2 von Sun eingeführt.
Auch die JVM hat eine ähnlich steile Entwicklung gemacht4 , die hauptsächlich die Effizienz der Programmausführung berührt.
Da die JVM die Verbindung zwischen Betriebssystem, Browser und Java-Plattform darstellt, ist sie der ideale Ansatzpunkt für politische Machtkämpfe.
Die Sun-Initiative »write once, run anywhere« hängt entscheidend davon ab, ob die J2SE und die zugehörige JVM in jedem Betriebssystem bzw. Browser installiert sind.
Diversifikation der Java-Plattform
Der Siegeszug von Java hat gleichzeitig eine Schattenseite. Die Java-Technologie muss für PDAs, Handys, Drucker, Smartcards oder Enterprise-Server zwangsläufig adaptiert werden.
Deswegen wurde unter der Parole »one size doesn't fit it all«, aber natürlich »one language is all you need« bei Sun mit der Diversifikation der Plattformen und der JVM begonnen (siehe auch Abb. 1.1).5
Plattform-
Abhängigkeit
Obwohl die Sprache an sich davon unberührt bleibt, wird dann jeder Java-Code wieder abhängig, und zwar von der Plattform. Zumindest ein Konkurrent von Sun sieht darin prinzipiell keinen Unterschied mehr zu einer direkten Bindung einer Sprache, z.B. Java, an das API des Betriebssystems.
Abbildung 1.1 Java-Plattform-Architektur
1.1.1 Code-Design ![down](common/down.gif) ![top](common/top.gif)
Java-Programme sind nicht monolithisch, sondern bestehen aus kleinen autonomen Einheiten, den Klassen (classes). Der Compiler (z.B. javac) speichert den Byte-Code jeder Klasse in jeweils eigene Dateien. Dies erlaubt es der JVM, Klassen einzeln und nur bei Bedarf (auch über ein Netzwerk) zu laden.
Klassen als ausführbare Einheiten
Um zu starten, muss der JVM nur die Klasse angegeben werden, die sie als erste laden und ausführen soll. Dazu muss diese Startklasse natürlich, abhängig von der Umgebung – Betriebssystem, Browser oder Web-Server –die entsprechende Funktionalität besitzen.
Die Kehrseite dieses Designs besteht darin, dass erst während der Ausführung Konflikte beim Nachladen von Klassen in Verzeichnissen bzw. im Netz entstehen, die bei traditionellen Programmen in der Regel schon vorher beim Linken auftreten.6
Klassen gehören immer zu einem Package, wobei Java-Packages (über ihre Namen) Hierarchien bilden können. Die J2SE enthält zurzeit ca. 1.500 Klassen, organisiert in 59 Packages.
Um zumindest für eine gewisse Zeit J2SE zu stabilisieren, werden neue Klassen in Extension Packages (wie z.B. Java3D, Java Media Framework JMF etc.) ausgelagert. Dies Pakete gehören damit allerdings auch nicht zu J2SE und müssen bei Bedarf zusätzlich installiert werden.
Interface
Java kennt bereits auf Sprachebene Interfaces.
|
Ein Interface fasst eine Gruppe zusammengehöriger Methoden unter einem Namen zusammen, der die gemeinsame Aufgabe dieser Methoden charakterisiert. |
Interfaces: Rollen, die Objekte spielen können
Ein Interface hat damit den Charakter einer Rolle, die ein reales Objekt beherrscht oder nicht. Somit sind Interfaces abstrakt, man kann von ihnen keine Objekte erzeugen.
Eine Klasse kann beliebig viele Interfaces implementieren. Jedes Objekt kann dann z.B. beim Methoden-Aufruf anstelle eines Interface-Parameters stehen, sofern die zugehörige Klasse das Interface implementiert hat.
Damit werden schwerwiegende Defizite der Vererbung unter Beibehaltung der Hauptvorteile wie Substitution behoben.
Methoden und Daten
Keine globalen Funktionen und Daten
Für C/C++-Konvertiten ist die Tatsache ungewohnt, dass es keine globalen Funktionen und Daten außerhalb von Klassen gibt. Der auszuführende Code ist immer in den Methoden (Methods) der Klassen enthalten.
Aufruf oder Zugriff mit Hilfe des
dot-operators
Da Methoden und Daten an Klassen oder deren Objekte gebunden sind, erfolgt der Aufruf einer Klassen-/Objekt-Methode oder der Zugriff auf Daten von außen über den zugehörigen Klassen- bzw. Objektnamen, separiert durch den Punkt (dot-operator)7 vom Methoden-/Datennamen:
Klasse.methode() bzw. objekt.methode()
Klasse.feld bzw. objekt.feld
Die Klammern müssen bei Methoden immer angegeben werden, auch wenn sie keine Parameter haben. Damit ist ein Methoden-Aufruf leicht von einem Datenzugriff zu unterscheiden.
Arrays
Wie bei C/C++ werden Arrays als geordnete Kollektion von Elementen mit gleichem Typ durch eckige Klammern deklariert, wobei auch der Zugriff auf ein Element über den Index in eckigen Klammern erfolgt.
Damit sind allerdings die Gemeinsamkeiten mit C/C++ auch schon erschöpft. Denn bereits die bevorzugte Art, in Java Arrays zu deklarieren, stellt sich folgendermaßen dar:
Deklaration eines Arrays
|
Angabe des Typs der Elemente, gefolgt von einer eckigen Klammer |
byte[] bArr; String[] sArr;
Da die Angabe der Größe bei der Deklaration nicht erlaubt ist, kann die Array-Variable ein Array beliebiger Länge referenzieren. Diese Art der Deklaration kann auch für die Rückgabe von Arrays aus einer Methode verwendet werden (was C/C++ ohnehin nicht erlaubt).
Anlage eines Arrays mittels new
Mit der o.a. Deklaration ist noch kein Array angelegt. Dies geschieht normalerweise mittels eines new-Ausdrucks und kann direkt bei der Deklaration oder auch zu einem späteren Zeitpunkt erfolgen:
byte[] bArr= new byte[10];
Die Variable bArr referenziert nun ein Array mit zehn Elementen vom Typ byte (Näheres zu byte: siehe 1.3).
Für kleine Arrays gibt es eine sehr praktische Kurzform, die neben der (impliziten) Anlage des Arrays bereits den einzelnen Array-Elementen Werte zuweist:
int[] iArr= {1,2,3};
Dies ist äquivalent zu:
int[] iArr= new int[3];
iArr[0]=1; iArr[1]=2; iArr[2]=3;
1.1.2 Java-Applikation ![down](common/down.gif) ![top](common/top.gif)
Applications, Applets, Servlets
Java-Code, der direkt (mittels einer JVM) im Betriebssystem ausgeführt wird, nennt man Applikation (Application), innerhalb eines Browsers Applet und innerhalb eines Web-Servers Servlet oder Java Server Pages (JSP).8
Die JVM muss bei jeder Startklasse einer Applikation natürlich einen ihr bekannten Einstiegspunkt haben. Dieser Einstiegspunkt ist die Methode main(). Sie muss immer wie folgt definiert werden:
public static void main(String[] args) { ...
}
Auf diese Weise kann jede Klasse zum Testen ihrer Funktionalität mittels main() (temporär) ausführbar gemacht werden, selbst wenn sie außerhalb des Packages nicht von anderen Klassen benutzt werden kann.
Beispiel einer ausführbaren Klasse
Mittels des String-Arrays args können Argumente für die Programmausführung übergeben werden:
class StartableClass {
public static void main(String[] args) {
// Feld length enthält die Länge des
Arrays
for (int i=0; i < args.length; i++)
// Methode print() des Feldes out der Klasse
System
System.out.print(args[i]+" ");
}
}
Diese Klasse kann nun – unabhängig von ihrem eigentlichen Zweck – als eigenständiges Programm, genauer als Applikation von der JVM (z.B. java) ausgeführt und getestet werden, z.B. mit vier Strings:
java StartableClass 2 good 4 u
Dies erzeugt auf der Textkonsole das nützliche Echo9 :
too good for you
1.2 Programmstruktur ![down](common/down.gif) ![top](common/top.gif)
Aufgrund der Konzeption von Java als Internet-Sprache war es zwangsläufig notwendig, Java mit einer konsistenten Konvention für die Programmstruktur auszustatten. Dies zeigt sich u.a. in der J2SE:
|
Modularisierung des Codes mit Hilfe des Package-Konzepts |
|
Ein hierarchisches Namenssystem, das es ermöglicht, Namenskollisionen global zu vermeiden |
Die Konvention beinhaltet eine Anleitung zur Abbildung der Package- und Klassennamen in die Verzeichnisstrukturen und Dateien unterschiedlicher Betriebssysteme. Damit müssen natürlich die Namen von Packages gültige Verzeichnisnamen bei allen Betriebssystemen sein.
1.2.1 Packages und Namespace ![down](common/down.gif) ![top](common/top.gif)
Package: Kollektion zusammengehöriger Klassen/Interfaces
Nach dem Vorbild von Modula werden alle Klassen in Java-Packages gekapselt. Ein Package besteht aus einer Kollektion von:
|
Klassen |
|
Interfaces (Schnittstellen) |
|
Subpackages |
Mindestens besteht es aus einem dieser Elemente. Ein Package kann also durchaus nur eine »Hülle« für Subpackages sein, d.h. selbst keine Klassen oder Interfaces enthalten.
Namespace
Ein Package bildet für die enthaltenen Mitglieder einen so genannten Namensraum (namespace).
Eindeutigkeit der Namen
Innerhalb des Namensraums müssen die Namen der Mitglieder eindeutig sein, außerhalb können sie immer über den vorangestellten Package-Namen identifiziert werden.
Damit wird das Problem der Eindeutigkeit auf die Stufe der Packages verlagert, d.h., für eine Internet-Anwendung muss beispielsweise gewährleistet sein, dass Package-Namen eindeutig sind.
Konvention für eindeutige Package-Namen
Sun hat sich für die Packages aus dem eigenen Haus die Namen beginnend mit java, javax oder sun reserviert.
Der Rest der Welt generiert eindeutige Bezeichnungen anhand der eigenen global eindeutigen Internet-Domain-Namen. Nach Java-Konvention kehrt man sie dazu um und schreibt alles durchgängig klein, also z.B.:
Domain Name |
Package-Name
startet mit |
Spezieller Package-Name |
MeinName.de |
de.meinname |
de.meinname.meinpaket |
OurCompany.com |
com.ourcompany |
com.ourcompany.project1.dbms |
IBM.com |
com.ibm |
com.ibm.sf.samples.addressbook |
Hierarchie mittels Subpackages
Die letzten beiden Beispiele zeigen hierarchisch angeordnete Packages, wobei ein Subpackage-Name vom übergeordneten Package-Namen durch einen Punkt getrennt wird.
Alle Package-Namen des SanFrancisco Business-Projekts von IBM beginnen z.B. mit com.ibm.sf, wobei Beispiele in einer Gruppe von Subpackages enthalten sind, die mit com.ibm.sf.samples beginnen.
simple vs. fully qualified name
Innerhalb eines Packages müssen die so genannten einfachen Namen (simple names) von Subpackages, Klassen und Interfaces eindeutig sein. Es können also keine zwei Mitglieder eines Packages den gleichen Namen tragen.
Beim vollen Namen (fully qualified name) wird der einfache Name um den vorangestellten vollen Package-Namen ergänzt.
Innerhalb des Subpackages java.awt gibt es z.B. ein Subpackage mit einfachem Namen image bzw. vollem Namen java.awt.image.
Java ist
case-sensitive
Damit ist u.a. ausgeschlossen, dass in java.awt ein weiteres Mitglied, z.B. eine Klasse mit Namen image existiert, wobei allerdings eine Klasse Image erlaubt ist, da Java zwischen Groß- und Kleinbuchstaben unterscheidet.
No-Name/unnamed/Default-Package
Obwohl »gute Sitte«, muss ein Package-Name nicht unbedingt angegeben werden. Fehlt die Angabe, so gehören alle angegebenen Klassen bzw. Interfaces zum default bzw. unnamed Package.
![Icon](common/T.gif)
Da weder die Anzahl der unnamed-Packages noch ihre Abbildung in ein reales Dateisystem festgelegt ist, sollten nur kleine Beispiele bzw. temporärer Code in einem default Package getestet werden. |
Für rein lokale Anwendungen kann die erwähnte Namenskonvention sicherlich ignoriert werden, für kommerzielle Anwendungen ist sie sehr hilfreich.10
1.2.2 Java-Code-Struktur ![down](common/down.gif) ![top](common/top.gif)
Compilation-Unit
Java-Code – genauer eine Übersetzungseinheit (Compilation-Unit) – besteht aus folgenden drei Elementen, die exakt in dieser Reihenfolge aufeinander folgen müssen:
Definieren und Importieren von Packages
|
einer Package-Deklaration (optional) |
|
Import-Anweisungen von anderen Packages (optional) |
|
Klassen bzw. Interface-Definitionen (mindestens eine) |
Im folgenden Beispiel wird zuerst ein Package deklariert, gefolgt von zwei Importanweisungen (Erklärung siehe 1.2.3) und einer Klasse:
package com.company.samples.test;
import java.awt.*;
import java.math.BigInteger;
// Anschließend Klassen und Interfaces
class Test1 {
...
}
Durch das vorangestellte Schlüsselwort package wird das Package deklariert. Fehlt die Zeile, handelt es sich um das unnamed Package.
1.2.3 Zugriff auf Klassen und Import ![down](common/down.gif) ![top](common/top.gif)
Klassen und Interfaces (nicht Subpackages!) im selben Package können sich gegenseitig über den einfachen Namen referenzieren. Darüber hinaus kann auch auf die fundamentalen Klassen und Interfaces von java.lang immer über den einfachen Namen zugegriffen werden.11
public erklärte Klassen
Um auf Klassen und Interfaces in anderen Packages zugreifen zu können, müssen diese dort public erklärt sein:
public class Test1 { ... }
Für den Zugriff auf public erklärte Klassen anderer Packages muss per Default der volle Name verwendet werden.
Import: Vereinfachter Zugriff auf Klassen anderer Packages
Da dies auf Dauer mühselig ist, kann mittels der Importanweisungen auf alle (oder nur eine) Klasse(n) bzw. Interface(s) des angegebenen Packages auch über den einfachen Namen zugegriffen werden.
Im Beispiel von 1.2.2 werden mit Hilfe des Schlüsselwortes import und des Metasymbols * 12 alle Klassen und Interfaces aus java.awt importiert, gefolgt vom Import genau einer Klasse BigInteger aus java.math.
Führt der Import allerdings zu Namenskollisionen, da in zwei Packages die einfachen Namen gleich sind, muss der Konflikt durch Angabe des vollen Namens beseitigt werden.13
1.2.4 Dateiorganisation und Kompilierung ![down](common/down.gif) ![top](common/top.gif)
![Icon](common/R.gif)
Die Abbildung des Package-Konzepts in ein Verzeichnis- und Dateisystem ist natürlich vom Betriebssystem abhängig. In Java gibt es hierzu die folgenden Regeln, die aber nicht unmittelbar zum Sprachkern zählen und somit durchaus Ausnahmen zulassen:
Regeln zu Packages,
compilation unit, Klassen und Dateisystem
1. |
Eine Übersetzungseinheit kann beliebig viele Klassen und Interfaces enthalten, wovon jedoch höchstens eine public erklärt werden kann. |
2. |
Eine Übersetzungseinheit wird in einer Datei mit der Extension .java abgespeichert. |
3. |
Der Name der Datei muss den Namen der Klasse bzw. des Interfaces haben, die public erklärt wird. Gibt es keine, kann der Name frei gewählt werden. |
4. |
Nach dem Kompilieren der Übersetzungseinheit wird der Byte-Code jeder Klasse bzw. jedes Interfaces in eine separate Datei mit Namen der Klasse bzw. des Interfaces und der Extension .class abgespeichert. |
5. |
Die Package-Hierarchie wird in eine entsprechende Verzeichnishierarchie aufgelöst, d.h., die .java- bzw. .class-Dateien befinden sich in Unterverzeichnissen, die den Package-Namen abbilden.14 |
Nur die vierte Regel muss von allen Java-Entwicklungsumgebungen eingehalten werden. Die anderen gelten für Entwicklungsumgebungen, die dateibasierend sind und zur Speicherung des Programmcodes keine Datenbank verwenden.15
Entsprechend der fünften Regel liegt im Beispiel 1.2.2 die Datei Test1.class des Packages com.company.samples.test bei Windows im Unterverzeichnis com\company\samples\test bzw. bei Unix im Unterverzeichnis com/company/samples/test.
Diese Regel besagt nicht, dass die .java-Dateien im selben Verzeichnis wie die zugehörigen .class-Dateien liegen müssen. Denn die Unterverzeichnisse können für .java- und .class-Dateien verschiedene Ausgangsverzeichnisse (Root-Verzeichnisse) haben. 16
Wäre die Klasse Test1 public erklärt, müsste die Übersetzungseinheit, die den Java-Code enthält, nach der dritten Regel in einer Datei Test1.java abgespeichert sein.
1.2.5 Ausführen einer Applikation ![down](common/down.gif) ![top](common/top.gif)
Dem Java-Interpreter, z.B. java, braucht nicht angegeben zu werden, wo sich die Klassen der Plattform (J2SE) bzw. der Extentions befinden.
![Icon](common/R.gif)
Für alle anderen Klassen, die zur Applikation gehören, sind folgende Regeln zu beachten. Der Interpreter sucht
Regeln zur
Ausführung von Applikationen
1. |
per default innerhalb des aktuellen Verzeichnisses die Klassen des unnamed Packages. |
2. |
per default unterhalb des aktuellen Verzeichnisses in einem Unterverzeichnis, das dem Package-Namen entspricht, nach den Klassen des Packages. |
3. |
unterhalb der Verzeichnisse, die entweder mittels der Umgebungsvariable CLASSPATH (des Betriebssystems) oder alternativ der Option –classpath (des Interpreters) gesetzt werden. |
Die flexibelste Methode ist wohl, mittels –classpath beim Aufruf die Unterverzeichnisse anzugeben. Die Angaben in CLASSPATH werden damit überschrieben bzw. ersetzt.
Aufruf einer
Applikation unter Windows
Werden z.B. nur Klassen aus dem Package j2buch.kap1 benötigt, wobei die Klasse j2buch.kap1.Test1 ausgeführt werden soll, dann kann die Klasse Test1 nach der zweiten Regel mittels
C:\JB\classes> java j2buch.kap1.Test1
aufgerufen werden. Dies setzt voraus, dass sich Test1 im Unterverzeichnis C:\JB\classes\j2buch\kap1 befindet.
Nach der dritten Regel kann Test1 auch mittels
java –classpath C:\JB\classes j2buch.kap1.Test1
aus jedem beliebigen Verzeichnis aufgerufen werden.
Eine weitere Möglichkeit ist die, alle benötigten Klassen in eine JAR-Datei test.jar zu packen, die Test1 als Main-Class-Attribut enthält, und diese mittels der Option –jar auszuführen, z.B.:
java –jar C:\JB\test.jar
Ausnahme (Exception):
Abbruch der normalen Programmausführung durch Exceptions
Fehler, die nicht durch den Compiler abgefangen werden können, d.h. erst bei der Ausführung in der JVM auftreten, werden durch »Auslösen einer Ausnahme« (throwing an exception) von der JVM signalisiert.
Diese Ausnahme kann dann entweder im Programm durch einen entsprechenden Exception-Handler behandelt, d.h. abgefangen werden, oder die JVM bricht die Programmausführung mit einer detaillierten Fehlermeldung (Art/Ort der Exception) ab.
1.3 Primitive Datentypen ![down](common/down.gif) ![top](common/top.gif)
Acht primitive Typen
Acht so genannte primitive Datentypen sind Bestandteil der Sprache, werden also vom Compiler direkt erkannt. Hierzu zählen ein logischer (boolean) Typ, ein Zeichentyp sowie sechs numerische Typen.
Daneben gibt es noch Referenz-, Klassen- und Array-Typen.
Integraler Typ
Zeichen und ganze Zahlen werden unter dem Begriff integraler Typ, float und double unter Floating-point-Typ zusammengefasst.
Die primitiven Datentypen sind in der nachfolgenden Tabelle kurz zusammengestellt:
Tabelle 1.2 Primitive Typen
Type |
Wertebereich |
Default-Wert |
Bit-Größe |
Anmerkung |
boolean |
true, false |
false |
1 |
|
char |
\u0000 .. \uFFFF |
\u0000 |
16 |
unsigned |
byte |
-27 .. 27 -1 |
0 |
8 |
|
short |
-215 .. 215 -1 |
0 |
16 |
|
int |
-231 .. 231 -1 |
0 |
32 |
|
long |
-263 .. 263 -1 |
0 |
64 |
|
float |
Float.MIN_VALUE ..
Float.MAX_VALUE,
Float.NaN,
Float.NEGATIVE_INFINITY,
Float.POSITIVE_INFINITY |
0.0 |
32 |
Darstellbare
Werte:
±1.402e-45 ..
±3.402e38 |
double |
Double.MIN_VALUE ..
Double.MAX_VALUE,
Double.NaN,
Double.NEGATIVE_INFINITY,
Double.POSITIVE_INFINITY |
0.0 |
64 |
Darstellbare
Werte:
±4.94e-324 ..
±1.79e308 |
Gegenüber C/C++ gibt es einen eigenen boolean-Typ, der eine Umwandlung von/nach Integer nicht zulässt, d.h., 0 oder 1 werden als Ersatz für false und true nicht akzeptiert (siehe 1.5).
Immer mit Vorzeichen (signed)
Alle numerischen Typen sind signed, d.h. erlauben Vorzeichen und haben eine fest definierte Größe, unabhängig von der Maschine bzw. dem Betriebssystem.
1.3.1 Regeln zu Operationen mit Zahlen ![down](common/down.gif) ![top](common/top.gif)
![Icon](common/R.gif)
Nachfolgend die wichtigsten Regeln zu Zahlen-Operationen:
Over- bzw. Underflow bei Integer-Werten
1. |
Bei Integer-Arithmetik stellt weder der Compiler noch die JVM sicher, dass der Wertebereich ausreicht. Ist das Ergebnis außerhalb des Wertebereichs, ist es schlichtweg falsch. |
ArithmeticException
2. |
Nur eine Division durch Null bzw. Modulo Null erzeugt eine ArithmeticException (Ausnahme siehe 1.2.5). |
Wertüberschreitung bei Floating-Point-Typen
3. |
Floating-Point-Typen kennen die Werte »nicht definiert«, d.h. NaN (Not-a-Number) sowie ±Unendlich, d.h. NEGATIVE_INFINITY bzw. POSITIVE_INFINITY, die Überschreitungen des Wertebereichs abfangen. |
4. |
Eine Operation mit einem »nicht definierten« Wert ergibt kein Ergebnis im normalen Wertebereich. |
5. |
Eine Operation mit NaN führt immer zum Ergebnis NaN. |
Beispiel17 18
Tabelle 1.3 Ergebnisse spezieller Floating-Point-Berechnungen
Berechnung von |
Ergebnis |
Anmerkung |
-0.0 / 0.0 |
NaN |
Undefiniert, d.h. NaN |
1.0 / -0.0 |
NEGATIVE_INFINITY |
es gibt eine negative Null |
(0.0 / 0.0) * (1.0 / 0.0) |
NaN |
NaN bleibt immer bestehen |
0.0 == -0.0 |
true |
-0.0 ist gleich 0.0 17 |
-0.0/0.0 == -0.0/0.0 |
false |
NaN ist mit nichts gleich18 |
1.4 Lexikalische Grundlagen ![down](common/down.gif) ![top](common/top.gif)
Aufbauend auf einem für Java erlaubten Zeichensatz – dem Unicode – besteht Java-Source-Code aus folgenden atomaren Elementen:
Bestandteile eines
Java-Programms
|
Whitespaces (Zwischenräume) |
|
Comments (Kommentare) |
|
Identifier (Bezeichner bzw. Namen) |
|
Separators (Trennzeichen) |
|
Literals (Literale) |
|
Keywords (Schlüsselworte) |
|
Operators (Operatoren) |
1.4.1 Unicode ![down](common/down.gif) ![top](common/top.gif)
Java verwendet als erlaubten Zeichensatz Unicode, womit es sich bereits von C/C++ in seinen Grundlagen unterscheidet.
Eine Sprache für Internet-Applikationen muss neben dem Standardzeichensatz für Englisch auch andere Zeichensätze wie Arabisch, Katakana, Griechisch etc. darstellen können.
Unicode-Tabelle
Da Unicode-Zeichen 16-Bit codiert sind, können prinzipiell 65.536 (=216 ) Zeichen dargestellt werden. Die Unicode-Tabelle ist in Bereiche für verschiedene Sprachen eingeteilt.
Kompatibel zu
ASCII, ISO-Latin-1
Im Tabellenbereich von 0...127 bzw. 0...255 ist Unicode identisch mit dem ASCII- bzw. ISO-Latin-1-Zeichensatz. Für diese Zeichen kann man also das oberste der beiden Bytes ignorieren.19
Da man selten eine Tastatur mit 65.536 Tasten zur Eingabe benutzt, gibt es eine spezielle Escape-Sequenz für Unicode-Zeichen (siehe 1.4.6).
1.4.2 Whitespace ![down](common/down.gif) ![top](common/top.gif)
Java ist frei formatierbar
(free-form)
Die Anzahl Leerstellen, Tabulatoren oder Zeilenumbrüche (Linefeed bzw. Carriage-Return) zwischen Token (Symbolen) können beliebig gewählt werden, sie werden ohnehin bei der lexikalischen Analyse durch den Compiler entsorgt.
1.4.3 Kommentare ![down](common/down.gif) ![top](common/top.gif)
Es gibt drei Arten von Kommentaren, die von C++ adaptiert wurden:
|
einzeilige: |
i=i+1; // oder i++; oder ++i; oder i+=1;
|
mehrzeilige: |
/* Arrays können im C/C++ oder im
Java-Stil deklariert werden */
int iarr[]; byte[] barr;
|
mehrzeilige Kommentare, die mit /** starten. Hieraus kann mit Hilfe von javadoc eine HTML-Dokumentation generiert werden. javadoc versteht einfache HTML-Formatierungen sowie mit @ beginnende Tags, d.h. Hinweise auf Text mit festgelegter Bedeutung: |
/** money factory class – a Pattern
@author BG
@version 0.9
<U>code name</U>: <B>W98 Green Banana</B>
*/
1.4.4 Identifier ![down](common/down.gif) ![top](common/top.gif)
Ein Identifier ist ein vom Programmierer wählbarer Name für Variablen, Marken, Methoden und Klassen mit folgenden Restriktionen:
|
Das erste Zeichen muss ein (Unicode) Buchstabe, ein Unterstreichungsstrich _ oder ein Währungssymbol $, £ bzw. ¥ sein. |
|
Ab dem zweiten Zeichen sind noch zusätzlich Ziffern erlaubt. |
|
Schlüsselwörter (siehe Tabelle 1.5) sind nicht erlaubt. |
Nachfolgend einige zulässige (erste Zeile) bzw. unzulässige Identifier:
_i__ £4 äß _123 Õre
2i ab/1 B-1 ab! a%b #a goto
1.4.5 Separator ![down](common/down.gif) ![top](common/top.gif)
Java verwendet neun Zeichen als Trennzeichen mit besonderer Bedeutung, wobei der häufigste Separator wohl das Semikolon ist, das Anweisungen abschließt. Die restlichen sind verschiedene Arten von Klammern, Komma und Punkt:
; , . ( ) { } [ ]
1.4.6 Literale ![down](common/down.gif) ![top](common/top.gif)
Literale:
konstante Werte
Im Gegensatz zu einem Identifier repräsentiert ein Literal einen konstanten Wert eines bestimmten Typs. Literale können in Ausdrücken, Zuweisungen und als Argumente beim Methoden-Aufruf verwendet werden.
Es gibt Literale zu den primitiven Typen, zur Klasse String, das null-Literal sowie noch Literale der Klasse Class, die im Folgenden kurz vorgestellt werden:
Logische Literale
Die einzigen Literale vom Typ boolean sind true und false.
boolean ok = false;
Zeichen-Literale
Zeichen-Literale müssen immer in Hochkommata eingeschlossen werden.
Hexadezimale Eingabe von Zeichen
Für Zeichen, die nicht mittels Tastatur eingegeben werden können, wird die Unicode-Tabellenposition in Form von (maximal) vier hexadezimalen Ziffern 0..F (Basis 16) mit dem Präfix \u eingegeben.20 0 Die Hex-Ziffern können groß A..F oder klein a..f geschrieben werden.
Für die Eingabe von speziellen Zeichen gibt es in Java wie C/C++ die nachfolgenden Escape-Codes:
Tabelle 1.4 Escape-Codes für Sonderzeichen
Escape-Code |
Zeichen |
'\''
|
Hochkomma (single quote) |
'\"'
|
Anführungszeichen (double quote) |
'\\'
|
Schrägstrich nach hinten (backslash) |
'\b'
|
Schritt zurück (backspace) |
'\t'
|
Tabulator (tab) |
'\n'
|
Zeilenschaltung (linefeed/newline) |
'\r'
|
Wagenrücklauf ( carriage return) |
'\f'
|
Seitenschaltung (form feed) |
Mit Hilfe des Escape-Codes lassen sich Unicode-Zeichen eingeben:
char c1='\u00c4';
System.out.print(c1=='Ä'); // :: true
Integrale Literale
Eingabe von ganzen Zahlen
Die als integrale Literale bezeichneten ganzen Zahlen vom Typ int oder long können dezimal, hexadezimal oder sogar oktal eingegeben werden, wobei die hexadezimale Eingabe mit 0x oder 0X und die oktale mit 0 beginnen muss.
Alle Literale sind per default vom Typ int. Wird an das Literal (das Suffix) l oder L angehängt, ist es vom Typ long.
int i= 0x10+10+010; // 16+10+8
System.out.print(i+" "+0x10L); // :: 34 16
Floating-Point-Literale
Eingabe von
Dezimalzahlen
Ein Floating-Point-Literal vom Typ float oder double ist eine Zahl mit Dezimalpunkt und/oder einem angehängten Exponent und/oder einem Suffix f oder F für float bzw. d oder D für double. Fehlt das Suffix, ist das Literal per default vom Typ double.
Der Exponent beginnt mit E oder e, gefolgt von einem optionalen Vorzeichen und dem Exponenten (möglicher Wertebereich siehe Tabelle 1.2). Damit sind alle nachfolgenden Zahlen gültige Floating-Point-Literale:
0. .0 +1f -6e+1
7.1E-1F
Dabei ist die letzte Zahl gleich 0.71 und vom Typ float .
String-Literale
Strings sind Zeichensequenzen und werden immer in Anführungszeichen (double quotes) gesetzt. Innerhalb des Strings können die einzelnen Unicode-Zeichen (wie bei Zeichen-Literalen) per Escape-Code oder hexadezimal eingegeben werden.
Die Anweisung
System.out.print("\"\u00c4\tÖ\tÜ\"\nNeue
Zeile");
gibt (unter Windows) zwei Zeilen auf der Konsole aus:21
"Ä Ö Ü"
Neue Zeile
String-Literale sind Objekte
String-Literale sind keine Werte vom primitiven Typ, sondern sind eine kurze elegante Art, Objekte der Klasse String anzulegen.
Somit können auf String-Literale alle Instanz-Methoden der Klasse String angewendet werden, wie z.B. die Methode length(), die die Länge des Strings zurückgibt:
System.out.print("".length());
// :: 0
Literal null
null: Kein Objekt referenziert
Neben den Variablen vom primitiven Typ gibt es noch Referenzvariablen, die auf Objekte von Klassen zeigen. Um anzuzeigen, dass eine Referenzvariable auf kein Objekt zeigt, wird das Literal null (ein Schlüsselwort) verwendet.
String s= null; // s zeigt auf kein String-Objekt
System.out.println(s); // :: null
System.out.println(s.length()); // Exception
NullPointerException
Die letzte Code-Zeile führt nicht zu einem Compilerfehler, sondern bei Ablauf des Programms zu einer NullPointerException, da von einem nicht existierenden Objekt keine Länge abgefragt werden kann.
Literale zur Klasse Class 22
Class-Literale
enthalten Klassen-Informationen
Die Klasse Class enthält Objekte zu allen Datentypen (inkl. sich selbst). Durch Anhängen von .class hinter einem beliebigen Typ kann man ein zu diesem Typ zugehöriges Literal vom Typ Class schaffen.
Class intTyp= int.class;
Dies kann u.a. zur Untersuchung von Klassen verwendet werden. Das nachfolgende Code-Fragment gibt alle Methoden der Klasse String aus (die Klasse Method ist aus Package java.lang.reflect zu importieren):
Class stringType= String.class;
Method[] methodArr= stringType.getMethods();
for (int i=0; i<methodArr.length; i++)
System.out.println(methodArr[i]);
1.4.7 Schlüsselwort ![down](common/down.gif) ![top](common/top.gif)
Keyword:
Identifier mit fester Bedeutung
Schlüsselwörter sind vordefinierte Identifier mit einer speziellen Bedeutung. Sie dürfen deshalb auch nicht als normale Identifier verwendet werden.
Es gibt zurzeit 59 Schlüsselwörter, die anhand ihrer Funktion in Kategorien eingeteilt werden können. Zum Beispiel gibt es für Bedingungen die Schlüsselworte if, else und switch und eine Gruppe von elf Schlüsselwörtern, die zwar reserviert (®) sind, aber nicht benutzt werden.
Tabelle 1.5 Java-Schlüsselwörter
abstract |
const ® |
float |
int |
protected |
throw |
boolean |
continue |
for |
interface |
public |
throws |
break |
default |
future ® |
long |
rest ® |
transient |
byte |
do |
generic ® |
native |
return |
true |
byvalue ® |
double |
goto ® |
new |
short |
try |
case |
else |
if |
null |
static |
var ® |
cast ® |
extends |
implements |
operator ® |
super |
void |
catch |
false |
import |
outer ® |
switch |
volatile |
char |
final |
inner ® |
package |
synchronized |
while |
class |
finally |
instanceof |
private |
this |
|
1.4.8 Operatoren ![down](common/down.gif) ![top](common/top.gif)
Operatoren sind spezielle Symbole für Operationen auf Operanden. Je nach Anzahl der Operanden, auf die der Operator angewendet wird, unterscheidet man unäre und binäre Operatoren sowie einen ternären Operator.
Java kennt 37 Operatoren, die anhand ihrer Funktion klassifiziert werden, wie z.B. arithmetische oder logische Operatoren. Operatoren werden in Kapitel 2 behandelt.
1.5 Konvertierung primitiver Typen ![down](common/down.gif) ![top](common/top.gif)
Numerische Typen können bei Bedarf ineinander konvertiert werden. Selbst der Typ char ist im Prinzip eine nicht negative Zahl zwischen 0..216 -1 und kann daher in eine ganze Zahl umgewandelt werden.
Keine Konvertierung von/nach boolean
Im Gegensatz zu C/C++ gibt es keine Konvertierung eines primitiven Typs von/nach boolean.
Konvertierung: widening vs.
narrowing
Es gibt zwei Arten der Konvertierung:
|
die widening Conversion, die Konvertierung in einen Typ mit einem größeren Wertebereich (siehe Tabelle 1.2) |
|
die narrowing Conversion, die Konvertierung in einen Typ mit einem kleineren Wertebereich |
1.5.1 Widening Conversion ![down](common/down.gif) ![top](common/top.gif)
![Icon](common/R.gif)
Eine widening Conversion wird vom Compiler automatisch, d.h. implizit durchgeführt. Nachfolgend wichtige Regeln zur dieser Art der Konvertierung:
Initialisierung bzw. Zuweisung bei byte, short und char
1. |
Literale vom Typ char oder int können Variablen vom Typ byte, short oder char zugewiesen werden, sofern sie im erlaubten Wertebereich liegen (wenn nicht, führt dies zu einem Fehler bei der Kompilierung, kurz C-Fehler). |
2. |
Ansonsten kann eine implizite Konvertierung nur in Richtung der Pfeile (siehe Abb. 1.2) erfolgen. |
3. |
Eine automatische Konvertierung findet – sofern notwendig – bei der Übergabe von aktuellen Argumenten an Methoden und bei Zuweisungen statt. |
Eventueller Verlust an Genauigkeit
4. |
Bei Konvertierung einer int oder long nach Floating-Point kann nicht der Erhalt der Genauigkeit garantiert werden. |
Abbildung 1.2 Richtung der impliziten Typumwandlung
Nach der zweiten Regel kann also der Typ byte vom Compiler z.B. in ein long konvertiert werden, aber nicht umgekehrt.
Die Typen byte und short können nicht automatisch in char sowie char nicht in byte und short umgewandelt werden.
Beispiele
byte b= 'a'; // siehe Ausnahme: wie b= 97;
char c1= 97; // siehe Ausnahme: wie c= 'a';
char c2= b; // C-Fehler: kein widening conversion
int i= 1L; // C-Fehler: kein widening conversion
b= i; // C-Fehler: kein widening conversion
b= 128; // C-Fehler: siehe Ausnahme
Wird nach der vierten Regel z.B. ein int (32 Bit) in eine float (32 Bit) umgewandelt, so bedeutet dies evtl. einen Verlust an Genauigkeit, da float, bedingt durch den zusätzlichen Exponenten, eine maximale Genauigkeit von nur sieben Dezimalziffern hat:
int i=1234567891;
float f= i;
System.out.println(f); // :: 1.23456794E9
Numeric Promotion bei Operationen
Operationen mit unterschiedlichen Typen
Nehmen zwei unterschiedliche primitive Typen (siehe Abb. 1.2) an einer Operation teil, werden sie vom Compiler vor der Operation auf einen gemeinsamen Typ konvertiert.
Dies nennt man auch numeric Promotion und läuft bildlich nach folgender Regel ab:
![Icon](common/R.gif)
|
Bei der Konvertierung wird der Typ gewählt, der am weitesten rechts in der Abbildung 1.1 steht, wobei man mit int beginnen muss. |
Regel für die
implizite numerische Umwandlung
Übersetzt in die vier »normalen« Regeln heißt das:
1. |
Ist einer der Operanden vom Typ double, wird der andere in ein double konvertiert. |
2. |
Ansonsten: Ist einer der Operanden vom Typ float, wird der andere in ein float konvertiert. |
3. |
Ansonsten: Ist einer der Operanden vom Typ long, wird der andere in ein long konvertiert. |
4. |
Ansonsten: Beide Operanden werden in ein int konvertiert. |
Bei dem nachfolgenden Code-Fragment führen i*i bzw. i*i*1. zu einem falschen Ergebnis.23 Die letzte Berechnung ist nach der ersten Numeric-Promotion-Regel allerdings wieder richtig:
int i= 1000000;
Die Reihenfolge der Operationen entscheidet
System.out.println(i*i); // :: -727379968
System.out.println(i*i*1.); // ::
-7.27379968E8
System.out.println(1.*i*i); // :: 1.0E12
1.5.2 Narrowing Conversion und Casting ![down](common/down.gif) ![top](common/top.gif)
Eine den Wertebereich einengende numerische Konvertierung ist nicht implizit, sondern nur explizit möglich.
Dazu stellt man einfach den gewünschten Typ in Klammern vor den zu konvertierenden Wert (Cast).
Fehler beim Cast
Cast: Explizites Konvertieren ohne Gewähr
Es ist allein die Aufgabe des Programmierers sicherzustellen, dass die Daten beim Cast nicht falsch werden, da z.B. im integralen Bereich die obersten Bits einfach abgeschnitten werden.
int i= 0xFFFF; // i hat
den Wert 65535
short s= (short) i; // s hat
den Wert –1
byte b1= 0, b2= 1, b3;
b3= b1+b2; // C-Fehler 24
b3= (byte)(b1+b2); // die 2. Klammer ist notwendig
float f= 0.0; // C-Fehler, richtig: f=
0.0F
Runden beim Cast
Ein Floating-Point-Typ wird in einen integralen Typ durch Abschneiden der Stellen hinter dem Dezimalpunkt umgewandelt:
System.out.println((int)10.9999);
// :: 10
1.6 Initialisierung von Variablen ![down](common/down.gif) ![top](common/top.gif)
Java kennt zwei Arten von Variablen:
Member bzw. Felder vs. lokale Variable
|
Member-Variablen, d.h. Variablen, die als Mitglieder bzw. Felder (fields) einer Klasse deklariert werden, |
Statische vs. Instanz-Variable
|
lokale Variablen25 (auch automatische Variable genannt), die lokal in einer Methode deklariert sind. |
Bei Feldern unterscheidet man zwischen
|
statischen Variablen, auch Klassen-Variablen genannt (static bzw. Class Variable), die es unabhängig von den Objekten – den Instanzen von Klassen – nur einmal pro Klasse gibt. Sie erkennt man an dem vorangestellten Schlüsselwort static. |
|
Instanz-Variablen (Instance Variable), die es für jedes Objekt gibt. |
Im Folgenden wird der Begriff Feld im Deutschen für Member-Variablen verwendet.
![Icon](common/R.gif)
Für die Initialisierung gelten folgende Regeln:
Ablauf und Werte der Initialisierung
1. |
Felder sowie die Elemente eines Arrays werden immer automatisch initialisiert, logische Variablen mit false, primitive mit 0 und Referenz-Variablen mit null. |
2. |
Die Initialisierung der statischen Variablen findet beim Laden der Klasse statt, bei Instanz-Variablen diyrekt nach der Erschaffung des Objekts26 (d.h. vor der Ausführung des Codes im Konstruktor). |
3. |
Lokale Variablen werden nicht automatisch initialisiert. |
4. |
Die Verwendung einer nicht initialisierten lokalen Variable führt zu einer Fehlermeldung des Compilers. |
Beispiel
Die nachfolgende Klasse InitTest enthält eine Klassen- und eine Instanz-Variable sowie eine Objekt-Methode.
In der Methode foo() wird ein int-Array und eine nicht initialisierte lokale Variable i deklariert, die bei Verwendung zu einem Fehler beim Kompilieren führt.
class InitTest {
static double d; // class field
String s; // instance field
void foo() { // Nonsens Name
int i; // lokale Variable
int[] iarr= new int[2]; // lokales int-Array
System.out.println(iarr[0]); // :: 0
System.out.println(d+" "+s); // :: 0.0 null
System.out.println(i); // C-Fehler: 4. Regel
}
}
1.7 Namenskonventionen ![down](common/down.gif) ![top](common/top.gif)
Jeder Programmierer entwickelt über kurz oder lang seinen eigenen Stil beim Codieren. Solange er isoliert arbeitet: kein Problem. Kritisch wird es erst, wenn er im Team arbeitet, sein Code von anderen verstanden und später modifiziert werden muss.
Hier kann Software-Engineering viel von älteren Ingenieurwissenschaften lernen, die Normen und Konventionen zur Conditio sine qua non für Ingenieure machen.
Deshalb soll das Kapitel mit einigen einfachen, aber wichtigen Namenskonventionen beendet werden, die das Leben in einer Java-Gemeinschaft sicherlich angenehmer gestalten:
![Icon](common/T.gif)
Allgemein
Konventionen
bei der Wahl der Namen
|
Für die Ausgabe ist Unicode eine »Offenbarung«. Dies bedeutet aber nicht, dass man nun Identifier in Deutsch, Spanisch oder Arabisch schreiben soll. Der ASCII-Zeichensatz ist immer die bessere Wahl, zumal für Klassen, die gleichzeitig auch Dateinamen sind.27 |
|
Besteht ein Identifier aus mehr als einem Wort, so beginnt jedes »innere« Wort mit einem Großbuchstaben (Ausnahme: Package). |
Package
Der gesamte Name wird in Kleinbuchstaben geschrieben und beginnt – sofern Eindeutigkeit erforderlich ist – mit dem umgekehrten Internet-Domain-Namen (siehe 1.2.1).
Klasse
Eine Klasse beginnt immer mit einem Großbuchstaben. Klassennamen enthalten in der Regel Substantive.28
MeineErsteKlasse XMLUtility
Interface
Ein Interface unterliegt aufgrund seiner Ähnlichkeit zu einer Klasse der gleichen Konvention. Damit lässt sich ein Interface allerdings aufgrund des Namens nur selten von einer Klasse unterscheiden.29 9
Dies stört nicht unbedingt, sofern man z.B. mit UML-Klassendiagrammen (siehe Kapitel 4, Modellierung und UML) arbeitet.
Alternativ kann man nach MS-MFC30 -Konvention jeden Namen mit dem Präfix I versehen.
IPerson IProduct IUnknown
Konstante
Eine Konstante (eine static final deklarierte Variable) vom primitiven Typ wird durchgängig groß geschrieben, wobei Wörter durch einen Unterstreichungsstrich getrennt werden:31
PI DEM_EURO_EXCHANGE_RATE
Methode, Variable und Parameter
Eine Methode, Variable oder ein Parameter beginnt immer mit einem Kleinbuchstaben.
Eine Methode sollte in der Regel mit einem Verb beginnen.
Der Name eines Parameters oder einer lokalen Variablen kann durchaus nur aus einem Buchstaben bestehen, sofern die Bedeutung klar ist.
isEmpty() setNewName(String s) firstName
1.7.1 Methodenname ![down](common/down.gif) ![top](common/top.gif)
Die Suche nach Methodennamen
Konventionen sind nur ein erster Schritt. Ein weiterer ist die Suche nach einem passenden Namen für eine Methode. 32
![Icon](common/Kaktus.gif)
Findet man keinen besseren Methodennamen als setzeDaten(), liefereEierWolleMilchFleisch() oder fubar(), sollte man sein Klassen-Design überdenken. Vielleicht gibt es ja doch bessere und für den Benutzer einsichtigere Methoden. |
1.8 Zusammenfassung ![down](common/down.gif) ![top](common/top.gif)
Das Wort »Java« steht für eine Technologie, die auf drei Säulen ruht, Sprache, Plattform und JVM. Klassen und Interfaces werden in Packages organisiert, die über mehrere Übersetzungseinheiten verteilt sein können.
Klassen kapseln Daten und Code und können mit Hilfe der Methode main() ausführbar gemacht werden. Die JVM lädt Klassen erst bei Bedarf und reagiert auf Laufzeitfehler mit Exceptions.
Unicode, Schlüsselwörter sowie acht primitive Datentypen inklusive ihrer Literale bilden das Fundament der Sprache. Numerische Datentypen können implizit oder explizit ineinander konvertiert werden.
Obwohl es auch zu Strings Literale gibt, zählen sie nicht zu den primitiven Datentypen, sondern sind Instanzen bzw. Objekte der Klasse String.
Felder einer Klasse sowie Array-Elemente werden automatisch initialisiert, nicht initialisierte lokale Variablen werden vom Compiler erkannt.
Zu Java gibt es akzeptierte Namenskonventionen, die man durchaus verletzen darf, sofern man Viren programmiert.
1.9 Testfragen ![top](common/15x15leer.gif) ![top](common/top.gif)
Zu jeder Frage können jeweils ein oder mehrere Antworten bzw. Aussagen richtig sein.
1. |
Welche Aussagen sind zu der ausführbaren Klasse Startable richtig? |
A: Startable muss public deklariert werden.
B: Sie wird in eine Datei startable.class kompiliert.
C: Startable enthält eine passende Methode main().
D: Startable kann in einer Compilation Unit mit Namen Test.java enthalten sein.
2. |
Welche main()-Methode kann als Startmethode für eine Applikation verwendet werden? |
A: public static void main(String arg[]) { ... }
B: public static void main(String[ ] a) { ... }
C: public static void main(string[] args) { ... }
D: public static void Main(String[] args) { ... }
3. |
Welche Kommentare sind korrekt gesetzt, sodass der Code fehlerfrei kompiliert wird? |
A: System.out.println(/**Kommentar**/"Hallo");
B: System.out.println(//Kommentar "Hallo");
C: System.out.println("Hal"/*//Kommentar*/+"lo");
D: System.out.println(\*Kommentar*\);
4. |
Welche Identifier sind gültig? |
A: $byte
B: __1
C: name-1
D: 1Name
E: operator
F: True
5. |
Welche Aussagen sind zu folgendem Code-Fragment richtig? |
char c= '1';
res= 2*c;
System.out.println(res);
A: Die Variable res kann vom Typ char sein.
B: Die Variable res muss vom Typ int sein.
C: Die Variable res kann vom Typ double sein.
D: Ist res vom Typ int, ist die Ausgabe: 2
E: Die zweite Codezeile ist fehlerhaft, egal von welchem Typ res ist.
6. |
Welche Aussagen sind zur Klasse InitTest richtig? |
class InitTest {
static boolean ok;
String s;
void test() {
int i;
//System.out.println(i);
}
}
A: s ist eine Instanz-Variable.
B: ok hat den Wert false.
C: Bei Entfernen der Kommentarsymbole // wird InitTest nicht kompiliert.
D: s hat den Wert Null.
7. |
Welche Aussagen sind richtig? |
A: Der Wertebereich von byte ist -27.. 27.
B: Die Anweisung char c= 65000; wird ohne Fehler kompiliert.
C: Die Anweisung char c= '/u0100'; wird ohne Fehler kompiliert.
D: Nach der Anweisung int i= 020; hat i den Wert 16.
E: 0x0101L ist eine long-Literal und hat den Wert 257.
F: "1" ist ein Literal vom primitiven Typ.
8. |
Was sind gültige Literale? |
A: 1,2
B: -.12e-1F
C: "\\a"
D: '\U003f'
E: True
9. |
Welche Aussagen sind zu folgendem Code-Fragment richtig? |
int i= (int) (1./0.);
System.out.println(i);
A: Der Compiler meldet in der ersten Zeile einen Fehler.
B: Bei der Ausführung wird eine Exception aufgrund der Division durch Null generiert.
C: Die Ausgabe ist: Infinity
D: Die Ausgabe ist: 2147483647
10. |
Welche Aussagen sind zu folgendem Code-Fragment richtig? |
String s= "1";
int i= (int) s;
System.out.println(i);
A: Der Compiler meldet in der zweiten Zeile einen Fehler.
B: Bei der Ausführung wird eine Exception aufgrund des unerlaubten Casts in der zweiten Zeile generiert.
C: Die Ausgabe ist: 1
1 Dies ist unweigerlich mit Kompromissen verbunden. Deshalb wird Java-Quereinsteigern empfohlen, parallel eine Einführung mit möglichst vielen Beispielen zu lesen (siehe Literaturhinweise).
2 API: Applications Programming Interface
3 deprecated: missbilligt, d.h. ersetzt und verbessert durch Neueres.
4 JIT: Just In Time Compilation, Hotspot Technology etc.
5 J2EE (Enterprise Edition), J2ME (Micro Edition), konfigurierbare virtuelle Maschine, KVM etc.
6 Für die korrekte Zusammenstellung und Distribution von Klassen werden deshalb Deployment-Werkzeuge mit den Entwicklungsumgebungen angeboten.
7 Der dot-operator ist an sich kein Operator, sondern ein Separator (siehe 1.4.5).
8 Sehr gebräuchlich ist die Bezeichnung Java App für eine Applikation oder ein Applet.
9 Allerdings nur, wenn StartableClass.class mittels classpath(-Option) auch gefunden wird (siehe auch 1.2.5) und die JVM diese Art von Humor versteht.
10 Womit auch public deklarierte Klassen bzw. Interfaces ausgeschlossen sind, da diese ja gerade zur Benutzung in anderen Packages vorgesehen sind (ohne Package-Name ist die Verwendung von public-Klassen vom aktuellen Verzeichnis abhängig).
11 Dies bedeutet den impliziten Import von java.lang.
12 Bedeutung von *: Sequenz von null oder mehr Zeichen, speziell hier aller Klassennamen.
13 Punkte im Package-Namen stellen Verzeichnistrenner des jeweiligen Betriebssystems dar.
14 Punkte im Package-Namen stellen Verzeichnistrenner des jeweiligen Betriebssystems dar.
15 Die fünfte Regel ist selbst für dateibasierende Entwicklungsumgebungen recht vage.
16 Bei JBuilder 4 liegen Source- und Class-Dateien in unterschiedlichen Verzeichnissen.
17 Mit dem Operator == wird auf Gleichheit hin geprüft.
18 Auch nicht mit sich selbst. Der Test auf Double.NaN erfolgt z.B. mittels:
Double.isNaN(0./0.).
19 Siehe hierzu auch 10.6.1
20 Alternativ gibt es noch eine oktale Eingabe von \000 bis \377 für die
ersten 256 Zeichen.
21 Eine mittels \n hart kodierte »neue Zeile« ist betriebssystemabhängig.
Besser ist println().
22 Sie werden hier nur der Vollständigkeit halber erwähnt. Zum Verständnis des
Kapitels sind sie nicht notwendig.
23 Gemäß Regel zur Integer-Arithmetik (siehe 1.3) wird die Überschreitung des Wertebereichs bei int und long nicht erkannt. Die Operationen werden von links nach rechts ausgeführt (siehe Kapitel 2, Operatoren).
24 Nach der vierten Regel wird mit byte, char und short nicht gerechnet, sondern mit int. Das Ergebnis ist also vom Typ int und muss explizit per Cast in Typ byte oder char umgewandelt werden (siehe zu arithmetischen Operationen auch Abschnitt 2.2).
25 Auch automatische Variable genannt
26 Dvor der Ausführung des Codes im Konstruktor
27 Wen das nicht überzeugt, der sollte einfach Excel-Tabellen mit (deutschem) VBA-Code für europäische Dependancen erstellen.
28 Zusätzlich sollte das Zeichen $ nicht im Klassennamen verwendet werden, da er zur Separierung von Namen innerer Klassen verwendet wird.
29 Außer wenn der Name Rollencharakter hat, wie z.B. Cloneable.
30 MFC: Microsoft Foundation Class (Library).
31 Bei konstanten Referenz-Variablen hängt die Konvention von der Semantik ab: Ist das Objekt, auf das die Referenz zeigt, auch konstant, d.h. immutable, so gilt auch hier die Großschreibregel.
32 Zu foo() bzw. fubar() siehe auch www.netmeg.net/jargon/terms/f/foo.html.
|