Java - DHBW Mosbach

Werbung
Einführung in die Programmierung mit Java (2. Semester IT + AI)
Prof. Dr. Herbert Neuendorf (DH Mosbach) [email protected]
(voraussichtliche) Inhalte :
z 1.Teil : Grundlegende Konzepte der Java-Programmierung
z
Grundlagen
„
Java: technische Grundlagen, JVM, Bytecode, ....
„
Typkonzept, primitive Datentypen, Casts, Zuweisungen, Operatoren, .....
„
Der grundlegende Aufbau von Java-Programmen
„
Kontrollstrukturen: Verzweigungen + Schleifen
„
Methoden, Rekursion
„
Blockkonzept, Namensraum, Sichtbarkeit
… möglichst zügig wegen C …
© H.Neuendorf
(1)
z
Fortsetzung Inhalte:
Klassen + Objekte
„
Sinn der Objektorientierung
„
Klasse, Objekt, Konstruktoren
„
Programmieren + Verwenden von Klassen - generelle Konzepte
„
Speziellere Konzepte :
Š
Š
Š
Š
Š
Š
Š
Š
Klassenvariablen + Klassenmethoden (statische Elemente)
Factories
Statische Initialisierung
Referenzen - Bedeutung der Objektvariable: Zeigerkonzept
Kein Unterlaufen der Kapselung durch Referenzen
Immutable Objects
Primitive Datentypen + Referenzen : Call by Value + Call by Reference
Überladen von Methodennamen
……….
z
Arrays – mit primitive Datentypen und Objekten
z
Zeichenketten (Strings)
z
Hüllklassen
© H.Neuendorf
(nur Einführung)
(2)
z 2.Teil : Objektorientierung
z
z
Fortsetzung Inhalte :
Vererbung - grundlegende Konzepte
„
Vererbung von Attributen + Methoden
„
Objekterzeugung und Konstruktoren in Vererbungshierarchien
„
Polymorphie - Typkompatibilität zwischen Ober- und Unterklassen
„
Upcast + Downcast, statischer + dynamischer Typ, späte Bindung
„
Abstrakte Klassen + Methoden
„
Finale Klassen + Methoden
„
Interfaces
„
Annotations
Pakete + Sichtbarkeiten von Klassen + Methoden
„
© H.Neuendorf
(3)
Einige Klassen aus Standardpaketen
z
Enums
z
Ausnahmebehandlung / Exceptions
z
Clonen von Objekten
z
Innere Klassen
z
Reflection
(4)
Fortsetzung Inhalte :
z 3.Teil : Datenstrukturen
z
Dynamische Datenstrukturen: Verkettete Listen + Bäume
„
Aufbau + typische Operationen
„
Stack + Queue als verkettet Liste
Je nach verfügbarer Zeit, evtl.
eher in Übungen eingebaut …
3. Semester (Prof. Deck)
Ereignisorientierte Programmierung
mit AWT + Swing
Threading
Fortsetzung
Persistenz
Netzwerk-Prg, RMI, Sockets
Datenströme
Collection Framework
Spezielle Java-Klassen
..............................
© H.Neuendorf
(5)
Literatur
Java + Einführung in Programmierung :
Deck, Neuendorf: Java-Grundkurs für Wirtschaftsinformatiker (Vieweg) ⊗
H. Mössenböck: Sprechen Sie Java (dpunkt)
D.Ratz, J.Scheffler, D.Seese: Grundkurs Programmieren in Java (Hanser)
Vorlesungsfolien (pdf) →
2.Auflage
www.dhbw-mosbach.de/index.php?id=1653
Umfassendere Überblicke über Java :
... (1000-Seiten Bücher - nicht erforderlich) ...
Kein Skript kann die Lektüre
eines guten Buches ersetzen !!
Ressourcen :
java.sun.com
Java Homepage von Sun Microsystems
Dort JDK: Popular Downloads → Java SE
java.sun.com/javase/6/docs/
JavaSE 6 Doku
www.java.de
Java User Group Deutschland
www.eclipse.org
Eclipse-Page mit allen Downloads
© H.Neuendorf
(6)
Voraussetzungen :
keine ... aber ...
Erwartungen
- Interesse, Mitarbeit, Kritik(!) während(!) der Vorlesung
- Immer fragen, wenn Unklarheiten auftreten !!
- Feedback, ob Tempo zu hoch oder niedrig
- Übungen möglichst eigenständig durchführen
- Skript nicht nur abheften, sondern zur Nachbereitung verwenden !
- Anregungen zur Verbesserung der Veranstaltung !
Ablauf …..
Vorlesung:
Blöcke zu 4-5 Stunden
Praktische Übungen: integriert
Software: SUN JDK 6
Eclipse IDE 3.5
Benotetes Programmierprojekt
© H.Neuendorf
(7)
Historie der Programmiersprachen
Maschinensprache
Assembler
C++
B. Stroustrup
Java
James Gosling
(Sun)
C#
Gründe für Java :
von C++ inspiriert, jedoch "bereinigt" .....
Vermeiden der Komplexität von C++ : hybrider Sprachumfang, echte Pointer, Speicherverwaltung ...
Java : klar objektorientiert, überschaubarer Sprachumfang, Garbage Collection .........
© H.Neuendorf
(8)
Java Historie :
Beginn: "OAK"- Projekt von SUN
Projekt anfänglich orientiert an Consumer Electronics
1990: Beginn der eigentlichen Entwicklung von Java durch J. Gosling & Bill Joy
1993: WWW
1995: JDK 1.0 von Sun + Browser HotJava (Applets!)
von allen gängigen Browsern unterstützt (Netscape, IE)
Dez. 98: JDK 1.2 - deutliche Erweiterung (Java 2)
[aktuell JDK 6]
Integrierte Entwicklungsumgebungen :
JBuilder (Borland)
Weiterentwicklungen:
NetBeans (Sun)
Eclipse
.....
JFC (Java Foundation Classes ),
SOAP, XML, neue Sprachfeatures, .......
JDK 1.0 ≈ 210 Klassen
JDK 1.1 ≈ 650 Klassen
JDK 1.2 ≈ 1250 Klassen .....
Java-Plattformunabhängigkeit
⇒ Konkurrent Microsoft
⇒ net-Offensive C#
Common Language Runtime
Java im Vergleich zu C++ : Weniger komplex, klarer, beherrschbarer, deckt 90% aller Fälle ab
⇒ " Langsamer für die Maschine, aber schneller für den Menschen " (= Entwickler)
© H.Neuendorf
(9)
Java = Sprache + Plattform
Programmiersprache :
Plattform :
"100%" objektorientiert – "alles" in Klassen
Fülle von Klassenbibliotheken (Paketen) :
Einheitliche Schnittstellen für alle unterstützen
Betriebssysteme → Aufrufe durch Laufzeitumgebung
für reale Plattform umgesetzt
Klare Syntax ohne Altlasten
Vermeiden komplexer Sprachmittel von C++
(Mehrfachvererbung, Operatoren-Überladen, ...)
Speicherverwaltung nicht programmiert, sondern
durch Garbage Collector geleistet
Infrastruktur für Internet-Anwendungen
Umgebung, die Unterschiede der realen
Betriebssysteme + Hardware "verbirgt" (kapselt) =
Virtuelle Maschine :
Für Entwickler stellt sich Java wie eigenständige
Plattform dar ⇒ Plattformunabhängigkeit !
Java-Anwendung
Editionen :
Klassenbibliotheken
1. Standard Edition für Fat Clients (Java SE)
2. Enterprise Edition für App-Server (Java EE)
3. Micro Edition für Kleingeräte (Java ME)
Virtuelle Maschine VM
Betriebssystem
(Smartphones, ....)
Hardware
© H.Neuendorf
Wo "lebt" Java ? → Java-Laufzeitumgebungen
(10)
Varianten :
Standalone-Applikationen :
1. Client JR für Applikationen
Normale Programme - von Java-VM-Interpreter
ausgeführt
2. Webbrowser mit Applets
3. Webserver mit Servlet Container
Applets :
4. Application Server mit EJB-Container
Spezielle Klassen, die in Browser mit integrierter JVM
ablaufen - besondere Sicherheitsrestriktionen !
Alle nutzen Java-Klassenbibliotheken und
werden in Java-VM ausgeführt.
Servlets + JSPs :
Unterschiede bestehen in Anwendungs-Struktur
und Umgebungen, in denen VM arbeitet.
Java-Klassen, die auf Webserver dynamisch HTML
generieren
Enterprise Java Beans (EJB) :
Umgebung: JDK / Java SDK
Services, die ein Enterprise Application Server
bereitstellt - u.a. transaktionale Dienste
www.java.sun.com
SUN: Java Development Kit (1.6 = 6)
Laufzeitsystem + Entwicklungstools
JRE: Java Runtime Environment
= nur JVM-Laufzeitbestandteile
© H.Neuendorf
VM: Java läuft überall .... !!
Vom Handy bis zum Server ........
⇒
durch Java als Sprache hat man Zugriff in fast allen
möglichen Plattformen und Ebenen .......
(11)
Varianten der Java-Laufzeitumgebung
Java-Client
Browser-Client
Java-Anwendung
Java-Applet
Klassenbibliotheken
Virtuelle Maschine VM
Betriebssystem
Hardware
Java-VM in
Browser
integriert
Klassenbibliotheken
Virtuelle Maschine VM
Webbrowser
Betriebssystem
Hardware
1. Frontend-Bereich:
Fat Client, Browser, lokaler Rechner
= ursprünglicher Anwendungsbereich von Java
© H.Neuendorf
(12)
Varianten der Java-Laufzeitumgebung
Webserver
Java-App-Server
Java-Servlet
Enterprise Java Bean
Klassenbibliotheken
Bibl. + Dienste
Virtuelle Maschine VM
Virtuelle Maschine VM
Servlet-Container
EJB-Container
Webserver
2. Backend-Bereich :
Betriebssystem
Betriebssystem
Java auf dem Server
Hardware
Hardware
+
3. Middleware-Bereich : Kommunikation von Objekten in verteilten Systemen
Frontend-Backend / Backend - DB / … :
Netzwerk, RMI, JDBC, Message Queues, WebServices, .....
© H.Neuendorf
(13)
Java-Laufzeitumgebung
Konzeption von Java → Write once - run everywhere
Java-Client
Java-Anwendung
Klassenbibliotheken
Plattformunabhängigkeit !
Keine Annahmen über Zielhardware oder Betriebssystem !
VM: Zwischenschicht, die BS und Hardware kapselt
"Prozessor", der in Software realisiert wurde
Virtuelle Maschine
a) als Maschine definiert, die eigene Maschinenbefehle interpretiert
(aus Sicht des Java-Programms)
Betriebssystem
b) setzt Anweisungen in plattformspezifische Anweisungen um
(aus Sicht der Plattform)
Hardware
⇒ VM muss für jede Plattform, auf der Java-Programme
laufen sollen, speziell implementiert werden
Konsequenz : In Java geschriebenes Programm
→ wird von Java-Compiler in Code für die VM kompiliert = Bytecode
→ kann von jeder Java-VM ausgeführt = interpretiert werden !
→ läuft auf jeder Plattform (BS, Hardware) für die VM zur Vfg steht !
⇒ Kein erneutes Anpassen, Kompilieren, Linken, ....
© H.Neuendorf
(14)
Java-Laufzeitumgebung
Kompilierte Programmiersprache
C-Compiler für Win
Maschinencode
für Win
Windows
Quellcode(s)
C-Compiler für Linux
Maschinencode
für Linux
Linux
VM-Infrastruktur
Java
C/C++:
Write once - compile everywhere
Java:
Write once - run everywhere
Java Compiler
Bytecode
Windows
maschinen-
JVM
unabhängig
Java Quellcode
Nachteile :
a) keine direkten Hardware-Zugriffe ⇒ zB keine Treiber in Java programmierbar
b) keine harten Echtzeitanforderungen erfüllbar - denn :
Garbage Collection unterbricht Ausführung in unregelmäßigen Abständen
© H.Neuendorf
Linux
(15)
Interpretierte Sprachen - Bytecode kompilierte Sprachen
Nicht dasselbe - inbesondere bei Performanz !
Interpreter : Ausführung ohne Optimierung
→ Durchläuft Programmtext, übersetzt + führt jede Zeile einzeln aus ⇒ Langsam !
Bytecode-Architektur : Zweiteilung der Programmbearbeitung (Compiler + Interpreter)
→ 1. Schritt :
Parsen + Analysieren des Programmtextes ( + Finden von Fehlern! )
Übersetzen in optimierte VM-Instruktionen = Bytecode
→ 2. Schritt :
Ausführen der im Bytecode enthaltenen VM-Instruktionen
⇒ "semi-kompilierte" Sprache :
Viel schneller als reine Interpreter
Langsamer als reine Compiler (C / C++ )
Java
Java Compiler
Bytecode
Windows
maschinenunabhängig
JVM Interpreter
Java Quellcode
VM = zusätzliche Schicht zwischen Programm und
Ausführungsplattform
© H.Neuendorf
⇒
Kostet Zeit !
Linux
(16)
Bytecode = Maschinensprache der JVM
Sequenz Opcodes (Maschinenbefehle) für JVM
Analyse mit JDK-Tool javap
Opcodes haben Nummer + Namen
Optionen : javap –help ↵
Ausgabe Opcodes :
zB: Opcode 96 = iadd = Addiere zwei Integer
javap –c –private nameClassFile ↵
Beispiel :
Java-Anweisung:
int y = x + 5 ;
JVM-Befehlsfolge:
iload_1
; lege Integerwert aus Variable 1 auf den Stack
bipush 5
; lege den konstanten Wert 5 auf den Stack
iadd
; addiere die beiden Integer-Zahlen
istore_2
; speichere das Ergebnis in der Variablen 2
Werte der Parameter werden in Bytecode übernommen :
In Bytecode :
21
1
16
5
iload
1
bipush 5
96
54
2
iadd
istore
2
Java
Java Compiler
Bytecode
Windows
maschinenunabhängig
JVM Interpreter
Java Quellcode
JVM Spezifikation :
> 150 Instruction Opcodes
Linux
© H.Neuendorf
(17)
JVM-Anatomie
Dynamischer
Class Loader
Garbage Collector
+
Class Files
(Heap)
Class File
Verifier
+
Standard Java
Klassen
Byte Code
Verifier
Execution Engine
<
Native Methods
Besonderer Aspekt : Sicherheit
Native Method
Linker
Security
Manager
Java Runtime System
Bsp: Appletcode
Class File Verifier
Byte Code Verifier
Security Manager
© H.Neuendorf
Betriebssystem
(18)
Java-Virtual Machine
Execution Engine : - "Herz" der JVM = virtueller Prozessor der virtuellen Maschine
- Führt Bytecode-Instruktionen der JVM-Spezifikation aus
Class Loader : - Lokalisieren + Laden + Verifizieren + Initialisieren + Finalisieren
der für Programmausführung benötigten Klassen
( .class-Files = Bytecode )
- dynamisch: erst wenn Klasse benötigt, wird sie in JVM geladen
Garbage Collector :
- Objekte werden von Programmen im Hauptspeicher angelegt (new)
- Speicher-Freigabe nicht durch Programm (kein delete)
- sondern durch periodisch laufende Speicherverwaltung der JVM
Native Method Linker :
- Aufruf von Routinen, die als plattformspezifischer Maschinencode vorliegen
- nicht in Java / Bytecode, sondern Kompilat anderer Sprache
Security Manager :
(DLLs, libs)
- Java-Laufzeitsystem definiert Sicherheitsrichtlinien
- werden bei Programmausführung vom Security Manager durchgesetzt :
- Überwachung von Java-Programmen = Durchsetzen von Restriktionen
( zB: Zugriff auf lokales Filesystem, Konnektieren an Fremdrechner,
Übertragen von Benutzerdaten, Abbrechen der JVM .......... )
© H.Neuendorf
(19)
Weiterentwicklung der Java VM : Java Hot Spot VM
Java Bytecode
Java
Interpreter
Java Bytecode
JDK 1.4
(2002)
Java Hot Spot VM von Sun in
zwei Versionen ausgeliefert :
JIT Compiler
Just In Time Compilation
Server VM und Client VM
/jre/bin/client/ …
/jre/bin/server/ …
mit unterschiedlich optimiertem
Start- und Ausführungsverhalten
JVM Runtime
JVM Runtime
Schlechte Performance
Gute Performance
Bytecode wiederholt auszuführender
Programmteile (hot spots) wird zur
Laufzeit vor Ausführung einmal in
Maschinensprache (Prozessorbefehle)
übersetzt :
Java Hot Spot VM
© H.Neuendorf
(20)
Warum Java ?
“Java: A simple, object-oriented, distributed, interpreted, robust, secure,
architecture neutral, portable, high-performance, multithreaded,
and dynamic language ... ”
einfach:
(Sun: The JavaLanguage – White Paper)
Keine Zeigerarithmetik, Mehrfachvererbung, komplizierte C++ Konzepte
objektorientiert:
Klassenenkonzept, Vererbung, Interfaces, …..
Kleiner Sprachumfang + umfangreiche Klassenbibliotheken
verteilt:
Unterstützt netzbasierte Anwendungen
interpretativ: Bytecode-Ansatz verbindet Vorteile interpretativer + kompilierter Sprachen
robust: Fehlerquellen aus C++ vermieden, Garbage Collection, ...
sicher: Bytecode Verifier, Security Manager, Code-Zertifizierung
architektur- (plattform-) unabhängig:
Bytecode + APIs abstrahieren von Hardware
portierbar: JVM interpretiert identischen Bytecode auf allen unterstützten Plattformen
leistungsstark: Langsamer als C++, aber meist ausreichend !
Thread-unterstützend: Sprachelemente + Klassen zur Synchronisation paralleler Threads
dynamisch: Dynamisches Laden + Initialisieren benötigter Klassen zur Laufzeit
© H.Neuendorf
Programmerstelluung - kompilierte Sprachen
(Java ist anders !)
(21)
Erfassen des Programms : Coding in Quellcodedatei
Ausführen des Programms : Maschinensprache in Binärdatei
Übersetzen + Ausführen :
Vorteil → hohe Geschwindigkeit + Compiler checkt Programm vor(!) Ausführung auf Fehlerfreiheit
Objektmodul
Compiler
Quellcode
Fehlermeldungen
Library
Library
Manager
(Bsp: C++)
Linker
Executable
Eingabedaten
Editor
BS
Ausgabedaten
⇒ Optimale Übersetzung zur Ausführung für spezielles BS, Prozessorfamilie
⇒ Ausführung auf verschiedenen Plattformen (Win, Linux) erfordert Neu-Compilieren !
Aber : Nicht ideal für Anforderungen heterogener Umgebungen (Internet !)
Gefordert ist eher "Write & compile once, run everywhere“ ..........
© H.Neuendorf
(22)
Übersetzen + Interpretieren in Java
Übersetzungseinheit in Java
ist die Klasse
JDK-Compiler ist
*.java
Quellcode
Editor
Compiler
Klassen
Paket
Fehlermeldungen
javac
Bytecode
*.class
Bytecode von
Klassen
Vorteil :
Plattformunabhängigkeit Bytecode
Eingabedaten
Bytecode deutlich effizienter interpretiert als
reiner Programmcode
Interpreter
Java-VM
Systemaufrufe
Maschinensprache
Prüfungen bei Compilierung + bei Ausführung
durch JVM
⇒ Vorteile Interpreter + Compiler kombiniert
Nachteil :
Ausgabedaten
BS
Hardware
Benötigte Klassendateien einzeln von JVM
einzulesen = zeitaufwendig
Compiler erzeugt plattformunabhg. Bytecode ⇒ durch Java-Laufzeitsystem interpretiert
Laufzeitsystem = Umgebung unter deren Kontrolle ein Programm ausgeführt wird
Java-Laufzeit = Java Virtual Machine : Kapselt Besonderheiten der Plattform
Vollzieht Ausführung des Bytecodes auf spezieller Plattform
Java-VMs für relevante Plattformen zur Verfügung gestellt - verstehen alle denselben Bytecode
© H.Neuendorf
(23)
Erstellen + Ausführen von Java-Programmen
Lauf-Zeit
PC / Webbrowser
Compile-Zeit
PC
Applikation /
Class Loader
Applet-Klassen + HTML
Test.java
javac
Lokaler PC
Netzwerk
Class File Verifier
Byte Code Verifier
Internet
Interpreter java
JVM
Test.class
(Bytecode)
Für jede im .java-File
enthaltene Klasse wird
eigenes .class-File
vom Compiler generiert
Hardware
Benutzte Klassen (class-Files) können
an unterschiedlichen Orten liegen.
Erst zur Laufzeit bei Bedarf
nachgeladen !
© H.Neuendorf
Durch java ausgeführte
Datei muss main() Methode enthalten ...........
(24)
Erstellen + Ausführen von Java Programmen
PC
Editor
JDK: Java Development Kit
Quelldode
Compiler + Interpreter
Test.java
Compile-Zeit
Werden aus Kommandozeile
aufgerufen z.B. :
C:\ Demos > javac Test.java
Java Compiler
C:\ Demos > java Test
javac.exe
Bytecode
Test.class
Lokaler PC
Netzwerk
Internet
Internet
Browser
JVM
Verwendung fremder Klassen :
Weitegabe kompilierter classFiles ohne Quellcode genügt !
Eingabe
Java Bytecode
Interpreter
java.exe
Hardware
© H.Neuendorf
Lauf-Zeit
Ausgabe
(25)
Java-Werkzeuge - Java Development Kit (JDK)
Kommandozeile :
javac
Compiler
java
JVM-Launcher
appletviewer
Darsteller für Applets
javadoc
Dokumentationswerkzeug
jar
Archivierung (Zusammenfassung von Files)
javap
Bytecode-Analyse
.........
............................ (vieles mehr ...)
C:\ Demos > javac Test.java
C:\ Demos > java Test
(Ergebnisse dort ausgegeben)
Finden JDK-Werkzeuge + eigene Klassen
mittels Umgebungs-Variablen :
SET PATH=C:\Java\ jdk1.6.0_02\bin
Kein statischer Linker da Java-Laufzeitsystem
benötigte Klassen dynamisch bei Bedarf zur
Laufzeit lädt durch Class Loader
javac
Editor
Entwickler
SET CLASSPATH=.;C:\MyFolder
java
Programmtext
Bytecode
Ergebnis
Interpretieren
+ Ausführen
Beispiel.class
Übersetzen
Beispiel.java
Integrierte Entwicklungsumgebung (IDE) → Eclipse :
Massive Unterstützung bei Erstellung, Verwaltung, Bearbeitung und Ausführung von Programmierprojekten
( Projektdarstellung, Wizzards, Debugger, Syntax-Colouring, ..... )
© H.Neuendorf
(26)
Struktur Programmiersprache
Sprachdefinition:
Sun → Java Language Specification
Fester Wortschatz :
Schlüsselwörter = reservierte Wörter
Neue Bezeichner :
Benutzerdefinierte Namen mittels zulässigem Zeichensatz
Zeichensatz :
Klein-/ Großbuchstaben in Java NICHT austauschbar!
Syntax:
Case Sensitive !!!
Regelt Bildung sinvoller Anweisungen aus Zeichen und reservierten Wörtern
Syntaxregeln = Metasprache
Ziffer ::=
(Backus-Naur-Form BNF-Syntax)
0|1|2 |3 |4 |5 |6 |7 |8 |9
Zahl::=
Ziffer { Ziffer }
Kleinbuchstabe::=
a|b|c|d|e|f| .......
Großbuchstabe::=
A|B|C|D|E|F| .......
Buchstabe::=
Kleinbuchstabe | Großbuchstabe
Bezeichner::=
Buchstabe { Buchstabe | Ziffer }
"Syntaktische Ableitung"
Syntaxdiagramm für " Zahl "
Ziffer
Sematik:
Bedeutung der einzelnen Sprachkonstrukte = Wirkung der Programmanweisungen
" Was bedeuten die Sätze der Sprache im jeweiligen Kontext? "
© H.Neuendorf
Grundkonzepte von Programmiersprachen
(27)
Ebene oberhalb Maschinensprache ⇒ Mittel der Abstrakton und Strukturierung :
Datentypen : (primitive + strukturierte)
Modellierung verschiedenartiger Größen, Sicherheit durch Typprüfung
Variablen + Konstanten :
Verwendung von Namen anstelle von Speicheradressen für Zugriff
Verknüpfung von Variablen und Konstanten zu Termen
Zuweisungen :
Speicherung von Ausdruckswerten in Variablen
Ablaufsteuerungsanweisungen : (Verzweigungen & Schleifen)
Manipulation des Programmverlaufs – Steuerung des Kontrollflusses
Unterprogramm :
(Prozedur, Funktion, Methode)
Kapselung von Programmteilen zur Wiederverwendung und übersichtlichen Strukturierung
↓
Klassen :
Zusammenfassung von Daten + Methoden in eigenständiger gekapselten Einheit
© H.Neuendorf
Zunehmende Komplexität
Ausdrücke :
Elementare Bestandteile von Java
A.) Elementare Symbole :
Namen : Bezeichnen Variablen, Konstanten, Typen, Methoden, Klassen, ....
Bestehen nur aus Buchstaben, Ziffern, ‘_‘ und ‘$‘
Nicht ' , # * ....
Erstes Zeichen muss Buchstabe, ‘_‘ oder ‘$‘ sein
(keine Leerzeichen !)
(Variable min ≠ Min)
Groß- und Kleinbuchstaben unterschieden - Case Sensitive !
Bsp :
x x12
birth_date
Ungültig :
1Wert
Hallo Welt
class
A'1
Schlüsselwörter : Reservierte Namen zur Kennzeichnung von Programmstrukturen etc.
Java-Schlüsselwörter ausschließlich in Kleinbuchstaben
abstract boolean break byte case catch char class const continue default do double else
extends final finally float for goto if implements import instanceof int interface long native new
null package private protected public return short static super switch synchronized strictfp this
throw throws transient try void volatile while
Zahlen :
Ganzzahlen :
a) Dezimalzahlen = Ziffern 0 ... 9
Bsp : 0, 127, 1024
b) Hexadezimalzahlen = Ziffern 0 ... 9 + a,b,c,d,e,f
→ Kennzeichnung durch 0x
(für 10,11,...,15)
Bsp : 0x1A = 16+10 = 26
c) Oktal = Ziffern 0 ..... 7 → Kennzeichnung durch 0
Gleitkommazahlen :
verschiedene Darstellungsweisen
Bsp :
© H.Neuendorf
3.2
3.
0.3E1
3E-1
3.2f
Bsp : 012 = 8+2=10
Kommateil mit Punkt !
3.2F
3.2d
3.2D
(28)
(29)
Java-Schlüsselwörter - Kategorien
Java Schlüsselwörter
Klassen / Objecte
class
interface
new
extends
implements
instanceof
return
Modifizierer
private
public
protected
abstract
final
native
static strictfp
synchronized
transient
volatile
Elementare Datentypen
byte
short
int
long
float
double
boolean
char
Schleifen
Bedingungen
Packages
do
while
for
break
continue
if
else
switch
case
default
package
import
© H.Neuendorf
Fehlerbehandlung
try
catch
throws
throw
finally
assert
Referenzen/ Konstanten
this
super
void
null
true
false
Einfache Elemente von Java
A)
Zeichen :
Einzelne in Hochkommata eingeschlossene Buchstaben, Ziffern - und Sonderzeichen
Bsp:
'x'
'+'
'3'
'z'
''
'\n'
Zeichenketten : Folge beliebiger in doppelte Hochkommata eingeschlossener Zeichen
Dürfen Zeilengrenzen nicht überschreiten
Bsp: "This is a simple string."
"§3 a + 2% #$"
" "
B) Variablen-Deklaration + Variablen-Initialisierung :
Deklaration : Jede Variable muss vor Verwendung deklariert = mit ihrem Typ angemeldet werden
Bei Programmausführung wird entsprechender Speicher belegt
Namenszweideutigkeiten sind unzulässig
Aufzählungen möglich - Deklaration endet mit Strichpunkt ;
Bsp: int x ;
short w, y, z ;
Initialisierung : Bei Deklaration kann bereits Initialwert mitgegeben werden
Spätestens vor erster Verwendung muss Variable expliziten Wert erhalten
Bsp:
int x = 100 ;
int y = 0, z = 5 ;
Kommentare : Vom Compiler ignorierte Erläuterungen im Quellcode
// hiermit wird Rest der Zeile zum Kommentar = Zeilenendkommentar
/* hiermit wird Klammerkommentar eingeleitet, der sich über beliebig viele Zeilen
erstrecken darf; er endet mit dem Zeichen:
*/
Klammerkommentare dürfen nicht geschachtelt werden !
© H.Neuendorf
(30)
B.) Variablendeklaration :
(31)
Datentypen : Jede Variable muss mit Typangabe deklariert werden
Vordefinierte Standardtypen + selbst deklarierte komplexe Typen ( = Klassen )
Typ legt fest:
a) welche Werte der Variablen zuweisbar sind
b) welche Operationen durchgeführt werden dürfen
Kernkonzept moderner Programmiersprachen → Compiler kann prüfen dass :
→ Variablen nur zulässige Werte erhalten + nur zulässige Operationen angewendet werden
⇒ statische Typprüfung beim Übersetzen (Compilezeit) vor Programmausführung (Laufzeit)
Standard-Datentypen :
a) ganze Zahlen:
8 Bits = 1 Byte
byte
8-Bit
-2 7 .....2 7-1
(-128 ... 127)
( 1Bit fürs Vorzeichen )
short
16-Bit
-2 15 .....2 15-1
(-32768 ... 32767)
int
32-Bit
-2 31 .....2 31-1
(-2147483648 ... 2147483647)
long
64-Bit
-2 63 .....2 63-1
Speicherverbrauch + Werte bei Programmausführung bedenken !
Gefahr : Bei Programmausführung können Werte vorkommen, die Bereich überlaufen !
Teilmengenbeziehung gemäß Wertebereich :
long ⊃ int ⊃ short ⊃ byte
⇒ Bsp: short-Wert kann long- oder int-Variablen zugewiesen werden, nicht aber byte-Varaiblen
Primitive Datentypen :
Haben keine weitere Struktur, können nur einen einfachen Wert aufnehmen
Im Gegensatz zu strukturierten Datentypen : Klassen → können mehrere Werte aufnehmen
© H.Neuendorf
(32)
Standard-Datentypen
b) Gleitkommazahlen:
float
32-Bit
größte Zahl : ≈ 3 ∗10 +38
double
64-Bit
größte Zahl : ≈ 2 ∗10 +308
⇒ double hat mehr signifikante Dezimalstellen + größeren Bereich als float
⇒ größere und genauere Gleitkommazahlen darstellbar
aber : Genauigkeit prinzipiell begrenzt ⇒ Rundungsfehler !
Wichtig bei Vergleichsoperationen !!
Teilmengenbeziehung :
Bsp: double d = 1.0;
double ⊃ float " ⊃ " long ⊃ int ⊃ short ⊃ byte
float f = 2.0f;
f=i;
// ok
i=f;
// Fehler !
Rechnen mit Gleitkommazahlen für Rechner
aufwändiger als mit ganzen Zahlen !
int i = 3;
i = (int) f ; // ok - Typumwandlung (type cast)
Bei Cast: Nachkommastellen abgeschnitten !
Default-Typ einer Java-Gleikommazahl
ist double !
double d = 3.14 ;
// ok
float f = 3.14 ;
// Fehler!
float f = 3.14f ;
// ok! float-Wert
double d = 1.0;
float f = 1.0f;
Typregeln in Ausdrücken beim "Mischen" der
Zahlentypen :
int i = 2;
... f + i ....
// float
Der "kleinere" Operandentyp wird vor Ausführung der
Operation in den "größeren" konvertiert . Der berechnete
Ausdruck bekommt dann den gleichen Typ wie seine
Operanden - zumindest aber den Typ int !
... d * i ....
// double
... s + s ....
// int !!
... f / 3 ....
// float
© H.Neuendorf
short s = 3;
... (float) i / 3 .... // float
(33)
Standard-Datentypen
b) Gleitkommazahlen:
float 32-Bit
double 64-Bit
Intern Darstellung von Gleitkommazahlen durch Vorzeichen, Mantisse, Exponent :
z = (-1)v ∗ Mantisse ∗ 2 Exponent
Darstellung mit verfügbaren Bits gemäß IEEE-Norm:
v
Exponent
Mantisse
float
1 Bit
8 Bit
23 Bit
double
1 Bit
11 Bit
52 Bit
Aufgrund exponentieller Zahlendarstellung
können mit float (32 bit) größere Zahlen als mit
long (64 bit) dargestellt werden, obgleich
weniger Bits verwendet werden – allerdings evtl.
auf Kosten der Genauigkeit !
Konsequenz für Wertebereich + Darstellung :
float →
Exponentialteil von 2 -127 bis 2 +127 (entspricht etwa 2∗10 -38 bis 2∗10 +38 )
Mantissen erlauben Darstellung mit ca. 7 Dezimalstellen Genauigkeit
double → Exponentialteil von 2 -1023 bis 2 +1023 (entspricht etwa 2∗10 -308 bis 2∗10 +308 )
Mantissen erlauben Darstellung mit ca. 16 Dezimalstellen Genauigkeit
Notation: Mit Dezimalpunkt
Durch Suffix f oder d als float oder double kennzeichenbar (Default double)
Bsp:
© H.Neuendorf
1.0
2.56f
4.45e-11
2.2E9f ......
( E oder e bedeutet 10 hoch )
Standard-Datentypen :
(34)
Kleine Fallen
Ganzzahlen :
1. Java schneidet bei Ganzzahlrechnungen ab, um Ganzzahl zu erhalten
⇒ Kommastellen ohne Rundung abgeschnitten !
Bsp:
double x = 1 / 2 ;
// in x 0.0 !
double y = - 3 / 2 ; // in y – 1.0 !
2. Ganzzahlenbereiche quasi zu Ring geschlossen
Bei Überschreiten positiven Bereichs → Wiedereintritt in negativen Bereich
Bsp:
byte b = 127 ;
b = (byte) (b + 1) ;
// in b nun -128 !
byte b = 120;
for( int i = 0; i<20; i++ ) { b++; }
// Überlauf – kein Fehler !!
3. Bei Rechnen mit byte- und short-Variablen wandelt Java zum Typ int !
Bsp:
byte a = 5 ; byte b = 10 ;
byte c = a + b ;
// Compilerfehler ! Typ von (a + b) ist int !
// ⇒ Stattdessen casten :
byte c = (byte) (a+b) ;
© H.Neuendorf
// ok!
..... Kleine Fallen
Fließkommazahlen :
1. Default double !
Bsp:
⇒
1 + 1.0 ist double,
(35)
1 + 1.0f ist float
float f = 1 + 1.0 ; // Fehler !
2. Rundung von Ganzzahlen auch bei Zuweisung zu Fließkommatypen !
⇒ double d = 1 / 2 ;
double d = 1.0 / 2 ;
// in d 0.0 !
1 und 2 als Ganzzahlen
// in d 0.5
1.0 als double-Zahl
double d = (double) 1 / 2 ; // in d 0.5
1 zu double gecastet
double d = 0.8 + 1 / 2 ;
1/2 liefert 0
// in d 0.8 !
3. Fließkomma-Berechnungen sind ungenau !
double d = 1.03 – 0.42 ; // in d steht 0.6100000000000001
Casting : → Castoperator :
( type ) x
Somit Fließkommatypen im
Grunde ungeeignet für
monetäre Berechnungen !!
explizite Typkonvertierung
1. Zuweisung an größeren Datentyp unproblematisch
Bsp: int i = 17;
float f = i ;
// ok – 17.0f
implizite automatische Typkonvertierung
2. Aber : Bei Cast zum kleineren Datentyp wird abgeschnitten !
⇒ Wertänderung !
Bsp:
float f = 17.35f ;
int i = (int) f ;
// in i steht 17 - Verlust Nachkommastellen !
Bsp:
short s = 258 ;
byte b = (byte) m ;
// in b steht 2 - "überstehende" Bits abgeschnitten !
© H.Neuendorf
c) Zeichen = Typ char :
Standard-Datentypen ..
Codierung mit 16bit = UC
Einzelnes Zeichen (≠ Zeichenkette) → in einfachen Hochkommata ' '
char ch1 = 'a' ;
Java-Codierung 16bit = 2 Byte-Unicode
char-Variablen können
Zahlenwerte [0 ; 65535]
direkt zugewiesen werden –
aber keine Werte < 0.
Zuweisung von GanzzahlVariablen nur mittels Cast
⇒ char auch "zahlenartig" aber ≠ short-Bereich
double ⊃ float ⊃ long ⊃ int "⊃ char ⊃" short ⊃ byte
⇒ Berechnungen : int n = 'c' - 'a';
(36)
Bedeutung : Zeichen am
Platz in UC-Tabelle
// n-Wert 2. Zwei Plätze weiter in UC-Tabelle
int k = 'a';
// k-Wert 97
short s = ch1;
// Fehler – char sprengt positiven Bereich von short – mit int ok!
char ch2 = (char) k;
// Bei Variablen nur mit Cast !
Binäre Zeichen-Codierung :
1 Zeichen = 1 Byte
⇒
256 Zeichen
Unicode : 1 Zeichen = 2 Byte
⇒
65536 Zeichen !
ASCII :
← Java
Erste Zeichen von
UC entsprechen
den ASCII-Zeichen
d) Zeichenkette = Typ String : Kein primitiver Standard-Datentyp !
→ In " " :
String s = "Hallo" ;
String z = "37.6" ;
→ Mit Operator + Zeichenketten-Konkatenation :
s = s + " Welt !" ;
→ String-Konvertierung wenn durch + String mit anderem Datentyp verknüpft :
String s2 = "Alter = " + 40.5 ;
© H.Neuendorf
s2 = 10 + 10 + " Alter" ; // Inhalt: 20 Alter
Java-Datentypen
(37)
Datentypen
Objekttypen
Referenztypen
Primitive Datentypen
Ganzzahltypen :
byte
short
int
long
Fließkommatypen :
float
double
boolsche Werte :
boolean
Zeichen :
char
*) Defaults zB wirksam
bei Initialisierung von
Objekt-Attributen und
Array-Inhalten …
Null-Referenz
Arrays
Objektreferenzen
null
Menge von
Objekten oder
primitiven
Datentypen
Elementare Datentypen
Typ
Länge
Wertbereich
byte
8 Bit
-128.....127
(byte) 0
short
16 Bit
-32768......32767
(short) 0
int
32 Bit
-2147483648....2147483647
long
64 Bit
< Bereich ± 2^64 >
float
32 Bit
-3.4028..E+38... 3.4028..E+38
0.0 f
double
64 Bit
-1.7976..E+308...1.7976..E+308
0.0 d
true / false
false
Unicode !
'\u0000' = (char) 0
boolean
char
© H.Neuendorf
Klassen / IF
16 Bit
Initialisierung / Default *)
0
0L
(38)
Elementare
Sprachkonstrukte
C) Ausdrücke : Zuweisungen, Operationen :
Jede Art von Anweisung in Java endet mit einem Semikolon ;
(Deklaration, Zuweisung, Methodenaufruf, Objekterzeugung ....)
Durch Compiler gecheckt !
Zuweisungen:
x=y+1;
x=x+1;
Rechter Ausdruck berechnet und links stehender Variablen zugewiesen
Zuweisungen nur erlaubt, wenn Typen beider Seiten zuweisungskompatibel !
Sonst Compiler Fehler → statische Typprüfung → verhindert LZ-Abbrüche oder falsche Werte
→ a) beide Seiten desselben Typs
oder
b) Typ linker Seite schließt Typ rechter Seite gemäß Typ-Teilmengenbeziehung ein
int i = 2, j = 5;
short s = 5;
i = j ; // ok
i = s ; // ok
byte b = 4 ;
s = i ; // Fehler!
Konstanten-Deklaration : final int MAX = 527 ;
Definition von Konstanten :
i = 300 ; // ok
b = 300 ; // Fehler!
// Schlüsselwort final
Compiler checkt
Dürfen ihren Wert nach einmaliger Initialsierung nicht mehr verändern.
Einmalige Initialisierung auch nach Deklaration möglich – sogar auch erst zur LZ !
Vorteil: Lesbarkeit + Wartbarkeit durch zentrale Pflege konstanter Werte an einer Code-Stelle
© H.Neuendorf
Zuweisungen und Operationen :
Arithmetische Ausdrücke :
(39)
Elementare
Sprachkonstrukte
z =-(3*x+y);
// "von links nach rechts ..."
Berchnung eines numerischen Werts aus Variablen und Konstanten
mittels zulässiger Operatoren
a) Unäre Operatoren :
Vorzeichenfestlegung durch + und Bsp:
4+-3
// liefert 1
→ "binden" am stärksten ........
-4+3
// liefert -1
b) Binäre Operatoren :
Übliche Vorrangregeln ⇒ Punkt vor Strich, durch Klammern änderbar
Addition +
Subtraktion -
Multiplikation *
Division / : Ergebnis bei Ganzzahlen eine Ganzzahl (ohne Rest)
4/3=1
Ergebnis bei Gleitkommazahlen eine Gleitkommazahl
Modulo % : bei Ganzzahlen der ganzzahlige Divisionsrest
bei Gleitkommazahlen:
4%3=1
( selten verwendet ......)
Gleitkomma-Divisionsrest von x/y
8.5 % 2.1 = 8.5 - 4 * 2.1 = 0.1
© H.Neuendorf
-7 % 2 = -1
Divisionsrest
Bei Ganzzahltypen ist /0
und %0 nicht zulässig
und liefert zur LZ
ArithmeticException
(40)
Arithmetik
1. Bei Ganzzahltypen ist /0 und %0 nicht zulässig - liefert ArithmeticException :
int a = 5 / 0
// Abbruch !!
2. Fließkommatypen können jedoch gegen Unendlich "überlaufen" !
Operationen können mathematisch "uneigentliche" Werte liefern :
NaN (Not a Number)
infinity
-infinity
double d = 0.0 / 0.0
// in d steht NaN !
float f
// in f steht infinty !
= 1.0f / 0f
double g = 5. % 0
// nicht direkt zuweisbar, aber mittels Hüllklassen
Weiterverarbeitung "pathologischer"
Werte mittels Hüllklassen (s.u.)
// in g steht NaN !
3. Strenge und nichtstrenge Gleitkomma-Arithmetik
strictfp
anwendbar auf Klassen,
Interfaces, einzelne Methoden
Bezieht sich nur auf Gleitkomma-Arithmetik-Operationen
strictfp :
Strenge Regeln für G.A.Os. ⇒ Auf allen VM-Implementierungen erhält man
bitgenau identische Ergebnisse
nicht-strict : Gelockerte Regeln für G.A.Os. ⇒ VM-Implementierung darf interne
Optimierungen anwenden, die zu leicht abweichenden Ergebnissen führen könnten
Wenn eine nicht-strict-Methode eine strictfp-Methode aufruft, so wird sie selbst insgesamt
strictfp ausgeführt. strictfp wird jedoch nicht vererbt.
Konstantenausdrücke mit G.A.Os. werden immer streng ausgewertet
© H.Neuendorf
Arithmetische Ausdrücke :
(41)
Operatoren
c) Inkrement- und Dekrement - Operatoren :
Erhöhung oder Erniedrigung des Werts von x um 1
x++ ;
++x ;
x- - ;
- -x ;
// entspricht x = x+1; bzw x = x-1;
→ nur auf Variablen anwendbar, nicht auf Ausdrücke: x = (x * y)++; // Fehler!
Vorsicht bei Verwendung in Ausdrücken !
Stellung Operator bestimmt Auswertreihenfolge !! :
int x = 1;
int y = ++x * 3 ; // liefert 6 für y
int y = x++ * 3 ; // liefert 3 für y
x hat am Ende in beiden Fällen Wert 2
Präfixform ++x : Erst x manipulieren, dann weiterrechen
Postfixform x-- : Erst Zuweisung durchführen, dann x manipulieren
d) Zuweisungsoperatoren :
Abkürzende Schreibweise für Operation und Zuweisung
Für x vom Typ T ist x op= y kürzere Schreibweise für :
int x += y; // x = (int)(x + (y) );
x /= y;
x -= y;
x %= y;
In besonderen Fällen
schnellere Auswertung
x = (T) ( x op (y) ) ;
Bsp: short a *= b+1; // a = (short)( a*(b+1) );
x *= y;
…. auch für alle anderen arithmetischen, logischen und Bit-Operatoren
© H.Neuendorf
(42)
Operatoren
e) Bitoperationen
(~, &, |, ^, <<, >>, >>>)
nur für Ganzzahltypen – und char
Verändern Bitmuster : Direkte Manipulation der Bits in Binärdarstellung
⇒ Liefern geändertes Bitmuster zurück
Und, Oder, Exclusiv-Oder :
Negation :
a
b
a&b
a|b
a^b
a
~a
0
0
0
0
0
0
1
0
1
0
1
1
1
0
1
0
0
1
1
1
1
1
1
0
Bsp :
x = 1010
y = 1100
x & y = 1000
x | y = 1110
x ^ y = 0110
~ x = 0101
~ y = 0011
Shift-Operatoren :
a << b
Schiebt Bits von a um b Stellen nach links und füllt mit 0-Bits auf
Bsp:
a >> b
Schiebt Bits von a um b Stellen nach rechts und füllt mit höchstem Bit von a auf
Bsp:
a >>> b
a = 1100 ⇒ (a >> 2) liefert 1111
Schiebt Bits von a um b Stellen nach rechts und füllt 0-Bit auf
Bsp:
© H.Neuendorf
a = 0110 ⇒ (a << 1) liefert 1100
a = 1100 ⇒ (a >>> 2) liefert 0011
(43)
Bitoperatoren
Bsp: Zahldarstellung mit fiktiven
4 bits im Zweierkomplement
Negation : ~
byte b = 3 ;
// ≡ 0000 0011
Höchstes Bit → Vorzeichen !
byte c = ~b ; // ≡ 1111 1100 ≡ - 4
// Wert von c ist - 4 !
Addition : &
byte b1 = 3 ; // ≡ 0000 0011
byte b2 = 1 ; // ≡ 0000 0001
bye c = b1 & b2 ; // ≡ 0000 0001 ≡ +1 ;
// Wert von c ist +1 !
Shift : Linksshift << und Rechtsshift >>
byte b = 2 ; // ≡ 0000 0010
byte c = (b << 1) ; // ≡ 0000 0100 ≡ +4
// Wert von c ist +4 !
Schieben von Bits nach links bzw rechts entspricht
Multiplikation bzw Division durch 2 ......
© H.Neuendorf
1 = - 23
Dezimal
+8
+7
+6
+5
+4
+3
+2
+1
0
-1
-2
-3
-4
-5
-6
-7
-8
0=+0
Bitmuster
nicht darstellbar
0111
0110
0101
0100
0011
0010
0001
0000
1111
1110
1101
1100
1011
1010
1001
1000
(44)
Java-Operatoren
Operatoren
mathematisch
Addition
Subtraktion
Multiplikation
Division
Modulo
Vorzeichen
Inkrement
Dekrement
+
*
/
%
+ ++
--
logisch
Vergleiche
Negation !
Konj. && &
Disj. || | ^
Für boolesche
Ausdrücke
Gleichheit
Ungleich
Größen
Referenz
Zuweisung
==
!=
< >
<= >=
instanceof
Zuweisung =
+= -= *=
.............
bitweise
Negation ~
und
&
oder
|
xor
^
Shift
>>,<<,
>>>
Auswertregeln :
→ von links nach rechts
→ gemäß Vorrangregeln
- "Punkt vor Strich"
- Klammern höchste Priorität
Besonderheit : Zuweisungsoperator =
x=y=z
© H.Neuendorf
ausgewertet als
x=(y=z)
⇒ Im Zweifel Klammern setzen !
(45)
Priorität der Operatoren - Vorrangregeln
Zusammengesetzter Ausdruck : boolean b = 4 + 3 < 7 * 2 - 3 ; // liefert true
Ausführungsreihenfolge der Operationen durch Priorität der Operatoren geregelt
Im Zweifel + zur Übersicht Klammern setzen !
Bezeichnung
Unäre Operatoren
Expliziter Cast
Multiplikative Operatoren
Additive Operatoren
Schiebeoperatoren
Vergleichsoperatoren
Vergleichsoperatoren
bitweise Und
bitweise XOR
bitweise Oder
logisches Und
logisches Oder
Zuweisungsoperator
© H.Neuendorf
Operator
++ -- + - ~ !
( <type> )
* / %
+ << >> >>>
< > <= >=
== !=
&
^
|
&& &
||
|
= += -= .....
hoch
Operation mit höherer Priorität
vor Operation niedrigerer Priorität
ausgeführt
Bsp : Punkt- vor Strichrechnung
Setzen von Klammern ändert
Auswertreihenfolge !
boolean b = 4+3 < 7 * (2 - 3);
// liefert nun false!
niedrig
(46)
Grundstruktur Java
Schlüsselwort class : Java-Programm stellt
selbst Klasse dar
Minimales ausführbares Programm :
class Name {
Start des Programms mit Ausführung der
zentralen Methode main()
public static void main ( String[ ] args ) {
// ..... Deklarationen .....
String[ ] args : String-Array, das bei
Programm-Aufruf gefüllt werden kann
// ..... Anweisungen ......
}
}
Zu jeder geöffneten Klammer
(Blockanfang) gehört auch eine
schließende Klammer (Blockende)
class Hallo { // erstes Programm
public static void main (String[ ] args)
{
void : Methode main() liefert keinen Wert
zurück
static : statische Methode - direkt
aufrufbar, ohne erst Objekt der Klasse zu
erzeugen
public : Methode main() nach außen
sichtbar, von JVM aufrufbar
String gruesse = "Hello World" ;
IO.writeln( gruesse ) ;
1. Speichern als gleichnamige Datei Hallo.java
}
2. Wechsel ins Quellverzeichnis
}
Quelldatei hat gleichen Namen wie
die Klasse + Extension .java
3. Aufruf JDK-Compiler :
javac Hallo.java
4. Ergebnis / Compilat :
Hallo.class
5. Ausführen durch Aufruf JVM :
© H.Neuendorf
java Hallo
(47)
Grundstruktur Java
In Java-Programmen kollaborieren
Klassen bzw. Objekte
// Erstes Programm
class Hallo {
Objekten werden Aufträge erteilt :
public static void main( String[ ] args ) {
String gruesse = "Hello World" ;
IO.writeln( gruesse ) ;
// Text
// Methodenaufruf
}
}
Hallo = Auftraggeber
Client
IO
Server
= Auftragnehmer
Klasse IO stellt Methoden zur Verfg. (s.u.)
Aufrufsyntax :
Objektname.Methodenname( Parameterliste ) ;
Hallo
writeln(..)
Kollaborationsdiagramm
Blöcke können geschachtelt werden
Methoden können Parameter haben oder
parameterlos arbeiten.
Methoden können Werte zurückliefern.
IO
Durch Semikolon wird Anweisung
abgeschlossen ;
(UML)
Paar von geschweiften Klammern { } mit
null oder mehr Anweisungen = Block
© H.Neuendorf
Hallo ruft Methode writeln() der
Klasse IO auf
Ein Block kann überall da stehen, wo eine einzelne
Anweisung verwendet werden kann - da ein Block
eine (zusammengesetzte) Anweisung ist
Ein- / Ausgabe
(48)
(I/O)
Wertbelegung von Variablen durch :
a) Initialisierung und Zuweisung im Quellcode
b) Einlesen von Tastatur oder aus Datei (Ausgaben auf Bildschirm oder in Datei)
In Java ist Ein-/ Ausgabe kein integraler Teil der Sprache, sondern Teil der Java-Pakete :
→ zahlreiche Klassen mit Methoden zum Einlesen / Ausgeben
(von Zahlen, Texten, Bitströmen, .... )
Handhabung nicht einfach ⇒ Vorerst Arbeiten mit Ein-/Ausgabeklasse
IO. java
Deren Methoden verbergen die Komplexität ......
class Hallo {
public static void main( String[] args ) {
IO.writeln( "Hallo Mosbach!" ) ;
IO.advance(3) ;
IO.writeln() ;
IO.writeln( 123456 ) ;
}
}
© H.Neuendorf
Tool-Klasse IO :
Methoden sind public + static
⇓
Können direkt ohne Instanziierung in
verwendet werden !
Konsolen-Eingabe / -Ausgabe mittels
(49)
IO.java
Ausgaben :
void advance (int n)
// gibt n Leerzeilen aus
void write (String s)
// gibt String s aus
void write (int i)
// gibt Zahl i aus
void writeln (String s)
// gibt String s aus + Zeilenvorschub
void writeln (int i)
// gibt Zahl i aus + Zeilenvorschub
void writeln ()
// Zeilenvorschub
... und noch einige mehr ....
Eingaben :
String readString ()
// liest vom Benutzer eingegebenen String von Konsole ein
int readInt ()
// liest vom Benutzer eingegebene Ganzzahl ein
……………..
Eingaben mit vorangestellter Eingabeaufforderung (prompt) :
String promptAndReadString (String s)
// gibt String s aus und liest String ein
int promptAndReadInt (String s)
// gibt String s aus und liest Integer ein
char promptAndReadChar (String s)
// gibt String s aus und liest ersten Buchstaben ein
double promptAndReadDouble (String s)
// gibt String s aus und liest double-Zahl ein
Runden von Kommazahlen auf n Kommastellen :
float round( float f, int n )
© H.Neuendorf
double round( double d, int n )
// liefert gerundete float- bzw double-Zahl
Konventionen in Java-Programmen
Keine Vorschrift, jedoch üblich !
Einheitlichkeit + Konsistenz erhöht deutlich Lesbarkeit der Programme
1. Nicht mehr als einen Befehl pro Zeile schreiben.
2. Die öffnende geschweifte Blockklammer "{" steht am Ende des vorangegangenen
Statements - oder in einer eigenen Zeile.
3. Wenn neuer Block mit "{" begonnen wird werden alle in diesem Block stehenden
Zeilen um einige Zeichen nach rechts eingerückt.
4. Das Blockendzeichen "}" wird stets so eingerückt, daß es mit der Einrückung der
Zeile übereinstimmt, in der der Block geöffnet wurde. Sinn: Vergessene Klammern
sind leichter aufspürbar.
Tips :
1. Zugehörige schließende und öffnende Klammern { ... } (...) [...] immer zugleich schreiben und
ihren Inhalt erst nachträglich einfügen, damit schließende Klammern nicht vergessen werden.
2. Umgeben Sie Operatoren mit Leerzeichen, damit Formeln besser lesbar werden.
Eventuell existieren firmeninterne Style-Guides ........
© H.Neuendorf
(50)
(51)
Kontrollstrukturen - Verzweigungen + Schleifen
A) Verzweigungen
Fortgang der Verarbeitung hängt von Bedingungen ab
if-Anweisung :
if ( <Bedingung> ) { <Anweisungen> }
else { <Anweisungen> }
Überprüfung Bedingung auf Wahrheit/ Falschheit bestimmt weiteren Programmfluss
Bedingung wahr ⇒ if-Zweig
Aufspaltung in zwei Zweige :
Bedingung falsch ⇒ else-Zweig
if ( x > y ) { max = x ; } else { max = y ; }
(else-Zweig kann fehlen)
Bedingung : Logischer Ausdruck vom Typ boolean
Anweisungsblöcke : Ausführung mehrerer Anweisungen ⇒ in Block { } zu fassen
if ( x < 0 ) { x = x + 1 ;
else
{ x=x -1;
IO.writeln (x) ; }
IO.writeln (x) ; }
Dangling else : Verschachtelte if-Anweisungen - ein else "hängt in der Luft" :
if ( a < b )
if ( a > 0 )
else test = b ;
test = a ;
// auf welches if bezieht sich dieses else ??
Regel : Ein else gehört immer zum direkt vorausgehenden if
© H.Neuendorf
(52)
Datentyp boolean :
( ≠ 0,1 !
Nur Werte true und false
≠ C/C++ ! )
Bei Vergleichen (relationalen Operationen) als Ergebnis zurückgegeben
Variablen zuweisbar :
boolean q = x < y ;
Nicht zu anderen Datentypen cast-bar !
Vergleichsoperationen : Vergleich zweier Operanden ⇒ liefern Booleschen Wert (true, false)
==
!=
>
<
>=
<=
gleich
ungleich
größer
kleiner
größer oder gleich
kleiner oder gleich
x == 3
x != y
x>y
x<y
x >= y
x <= y
( nicht : x = 3 ; Zuweisung, kein Vergleich ! )
Prüfung gegen
NaN-Werte liefert
immer false
Verknüpfung von Booleschen Termen durch Operatoren :
And:
x && y (bzw &)
Or :
x || y (bzw | )
XOR : X ^ Y (entweder oder)
if ( 0 <= x && x <= 10 || 100 <= x && x <= 110 )
if ( ! ( x < 10) )
{ y=x; }
{ x = 20 ; }
Vorrangregel :
Im Zweifel Klammern setzen ............... !
== bindet stärker als ! bindet stärker als && bindet stärker als ||
a && b == c && d
© H.Neuendorf
hat Bedeutung von
a && (b == c ) && d
Not:
!X
(53)
Kurzschlussauswertung :
lazy evaluation
Optimierungsleistung der JVM :
Auswertung eines Vergleichsausdrucks wird abgebrochen, wenn Gesamtergebnis logisch feststeht
d.h. unabhängig ist von Auswertung der nichtausgewerteten Teile
&&-Verknüpfung : Wenn schon erster Teil false, dann auch Wert des Gesamtausdrucks false
|| - Verknüpfung : Wenn schon erster Teil true, dann auch Wert des Gesamtausdrucks true
if ( y == 0
Bsp:
if ( x < 0
a
b
w
w
f
&& ++x / y > 10 ) ...... // Wenn y != 0, dann ++x / y nicht berechnet !
|| --x / y < 10 ) ......
a && b
// Wenn x < 0, dann --x / y nicht berechnet !
a && b
a || b
a^b
w
w
f
w
f
w
w
w
f
f
w
w
a
f
f
f
f
f
b
a
b
Umgehung
Kurzschlussauswertung durch
Operatoren &
(statt &&) bzw |
(statt || )
Bei Operanden-Typ
boolean wirken & und |
als logische Operatoren,
nicht als Bit-Operator
a || b
Ternärer Operator :
© H.Neuendorf
int a = 10; int b = 1;
int c =
a>5 ?
2*b : 3*b ;
(54)
Kompakte Entscheidungsabfragen
// Ausführlich :
char antwort = IO.promptAndReadChar( "Springt Auto an? ( j/n )" ) ;
if ( antwort == ' j' ) { IO.writeln( "prima!" ) ;
else { IO.writeln( "schlecht!" ) ; }
// Abfrage
}
// Kompakte Formulierung :
Zusammenfassung von Abfrage + Bedingungsprüfung
if ( IO.promptAndReadChar("Springt Auto an? ") == ' j ' ) {
IO.writeln( "prima!" ) ;
}
else { IO.writeln( "schlecht!" ) ; }
// Zugleich Initialisierung Variable zur weiteren Verwendung
char antwort ;
if ( (antwort = IO.promptAndReadChar("Springt Auto an? ") ) == ' j ' ) { /* … */ }
// Verwendung von antwort ……
Prinzip :
Abfrage wird in Bedingung der Verzweigung eingebettet
Abfrage zuerst ausgewertet →
© H.Neuendorf
liefert Wert zurück, der dann für Vergleich zur Vfg. steht
Kontrollstrukturen : switch -Anweisung
Wert-Prüfung eines ganzzahligen Ausdrucks vom Typ
Davon abhängig wird verzeigt :
int month ;
(55)
Mehrweg-Verzweigung
int, short, byte oder char →
Muss mit case-Label
beginnen ….
int days ;
month = IO.promptAndReadInt( "Monats-Nummer = " ) ;
switch( month )
Jeder einzelne
case-Fall muss
eindeutig sein !!
{ // dürfte auch zusammengesetzt sein
// Case-Marker mit möglichen Alternativen
case 1: case 3 : case 5 : case 7 : case 8 : case 10 : case 12 :
days = 31; // wenn Alternative zutrifft, wird Anweisung ausgeführt
break ;
Auch negative
ganzzahlige
Werte erlaubt
// wichtig: damit switch verlassen wird !
// sonst :
folgende Anweisungen auch ausgeführt !
case 4 : case 6 : case 9 : case 11 :
days = 30; break ;
case 2 :
Lesbarkeit: case gegenüber switchAnweisung eingerückt. Zugehörige
Befehle werden nochmals eingerückt
days = 28; break ;
default :
// optionaler Default-Zweig - ausgeführt, wenn kein anderer zutrifft
IO.writeln( "Kein gültiger Wert!" ) ;
}
© H.Neuendorf
Es kann nur höchstens einen default-Zweig geben
Vergleich mit if-Sequenzen :
Wenn kein Fall zutrifft und kein default-Fall angegeben,
bleibt switch-Anweisung ohne Wirkung
Lesbarkeit + Effizienz !
switch –Anweisung :
switch ( <Ausdruck> ) {
case <Konstante> :
<Anweisung>
// .................
<Anweisung>
break ;
case <Konstante> :
<Anweisung>
// .................
<Anweisung>
break ;
default :
<Anweisung>
// .................
<Anweisung>
}
© H.Neuendorf
Ausdruck : Mit ganzzahligem Wert vom Typ int, short,
byte oder char - nicht aber Typ long !
(56)
Case-Kombinationen : Mehrere Alternativen gemeinsam
behandelbar durch Fall-Aufzählung
char m = 'B' ;
switch( m ) { // Variable vom Typ char
case 'A' : IO.writeln( "Das A wars" ); break;
case 'B' : IO.writeln( "Das B wars" ); break;
default : IO.writeln( "Sonst was" );
}
Sonderformen :
final int c1 = 10; final int c2 = 20;
int n = 10;
switch( n ) { // Benamte Konstanten als Case-Werte
case c1 : IO.writeln( "Die 10 wars" ); break;
case c2 : IO.writeln( "Die 20 wars" ); break;
default : IO.writeln( "Sonst was" );
}
public int getValue( int n ) {
switch( n ) { // Verlassen mit return-Anweisung in Methoden
case 1 : return 100 ;
case 2 : return 200 ;
In jeden case sind auch weitere
Fallunterscheidungen oder
default : return 500 ;
Schleifen einbaubar.
}
Wird rasch unübersichtlich !
}
B) Schleifen
Wiederholte Ausführung von Anweisungsfolgen
while - Schleife
Kontrollstrukturen
Abweisschleife :
while ( <Bedingung> ) { <Anweisungen> }
Prüfung Fortsetzungs-Bedingung vor jedem Schleifendurchlauf.
Bedingung ist Ausdruck, der Booleschen Wert liefert ( true oder false )
⇒ Eventuell Schleife nie betreten / durchlaufen, wenn Bedingung nicht zutrifft !
Zusammenfassung mehrerer Anweisungen in einen Anweisungs-Block { ... }
int i = 1 ; int sum = 0 ;
while( i <= n ) {
int n = 5 ;
// Abbruch: wenn i größer als n ⇒ Schleife verlassen
// wird vor jedem neuen Durchlauf mit aktuellen Werten geprüft
sum = sum + i ;
i++ ;
// wenn i = 6 erreicht, wird Schleife nicht mehr durchlaufen!
}
IO.writeln( sum ) ;
// hier wird Programm nach Verlassen der Schleife fortgesetzt
Vermeiden von Endlosschleifen : Schleife muss terminieren ⇒ Abbruchbedingung checken !
© H.Neuendorf
(57)
Kontrollstrukturen
do-while - Schleife
Durchlaufschleife, nicht abweisend :
do { <Anweisungen> } while ( Bedingung )
Prüfung der Fortsetzungsbedingung erst am Ende jedes Schleifendurchlaufs
⇒ Schleifenrumpf wird somit stets mindestens einmal betreten und ausgeführt !
int i = 1 ;
int sum = 0 ;
int n = 5 ;
do {
sum = sum + 1 ;
// Anweisungen werden mindestens einmal ausgeführt !
i ++ ;
} while( i < n ) ;
IO.writeln( sum ) ;
// wenn i = 5 wird Schleife verlassen
// hier wird Programm nach Verlassen der Schleife fortgesetzt
Anm:
do{ anweisungen } while( !bedingung )
entspricht dem Konstrukt do ... until anderer Sprachen
© H.Neuendorf
(58)
Kontrollstrukturen
for - Schleife
(59)
Zählschleife
Anzahl Durchläufe steht fest. Anzahl Durchläufe durch Laufvariable gezählt.
Dreiteiliger Schleifen-Kopf :
for ( <In>; <Fb>; <V> )
a) Initialisierungsteil :
{ <Anweisungen> }
legt Startwert der Laufvariablen fest
b) Fortsetzungsbedingung : wird jedesmal vor Betreten der Schleife geprüft
c) Veränderungssteil :
int sum = 0 ;
wie while-Schleife !
wird nach jedem Durchlauf ausgeführt → verändert Laufvariablenwert
int n = 6 ;
for( int i=1; i <= n; i++ ) {
sum = sum + 1 ;
IO.writeln( "Durchlauf Nr. " + i ) ;
// chars in UC-Tabelle angeordnet :
for( char n='A'; n <='Z'; n++ ) {
IO.writeln( "Hier : " + n ) ;
}
}
IO.writeln( sum ) ; // Programm fortgesetzt
Initialisierung + Veränderungsteil können aus mehreren Anweisungen bestehen - mit Komma trennen
Komplexerer Schleifenkopf :
for ( int i = 1, sum2 = 0 ;
© H.Neuendorf
i <= n ;
i++ , sum2 = sum2 + 2 ) { /* ... */ }
Verschieden typisierte
Laufvariablen müssten
außerhalb for-Schleife
deklariert werden
(60)
Kontrollstrukturen
for - Schleife
Schleife kann durch entsprechende Anweisungen auch dekrementiert werden :
for ( int i = 10 ; i > 3 ; i = i - 3 ) { ............................ } // i nimmt Werte 10, 7, 4, 1 an
Alle Schleifen können geschachtelt werden :
// Multiplikationstabelle :
Rumpf einer Schleife kann wieder Schleife enthalten
Jeder Teil des for-Schleifenkopfs darf
weggelassen werden :
int n = 10 ;
int mult ;
for( int i = 1; i <= n; i++ ) {
for( int j = 1; j <= n; j++ ) {
mult = i * j ;
IO.write( mult ) ;
}
IO.writeln( );
Fehlende Initialisierung oder Veränderung ⇒
quasi Übergang zur while-Scheife :
int i = 1; int n = 10 ;
for( ; i<=n; ) { IO.writeln( i++ ) ; }
Keine Fortsetzungsbedingung ⇒ true ⇒
Endlosschleife :
for( int i=1 ; ; i++ ) { IO.writeln( i ) ;
}
// i = 100 ;
j = 50 ;
Fehler !!
Endlosschleifen :
Die im Schleifenkopf deklarierte Laufvariable ist nur innerhalb Schleife gültig
© H.Neuendorf
for ( ; ; )
{....}
while (true) {.....}
}
Kontrollstrukturen
break
(61)
+ continue
Strukturierte Schleifenabbrüche durch break-Anweisung :
Kein goto
Abbruch des aktuellen Durchlaufs + aller folgenden Schleifendurchläufe
Sinn : Abfangen von Situationen, die weitere Ausführung sinnlos machen
aber : Schlechter Programmierstil → Programmverlauf unübersichtlicher ⇒ vermeiden !
→ Verstreuung Programmlogik
⇒
Fortsetzungsbedingung im Schleifenkopf !
int sum = 0 ;
Sprünge aus while-, do-, for-Schleifen :
int z = 100 ;
break → direkt hinter Schleifenende
while( true ) {
sum = sum + z ;
continue → Abbruch aktueller Schleifendurchgang + Sprung zur Wiederholungsbedingung der Schleife + Fortsetzung mit
nächstem Durchgang
IO.writeln( sum ) ;
if ( sum > 1000 ) break ;
}
Verlassen äußerer Schleifen durch Bezug auf Label :
für break und continue
L1: for ( ; ; ) { ............ // Label an äußerer Schleife
for (; ; ) { .... if (...) break ;
/* exit inner loop */
if( … ) break L1 ; /* exit outer loop */ }
}
// Verwendung continue :
for( int n=-10; n<=10; n++ ) { if( n == 0 ) { continue ; }
© H.Neuendorf
IO.writeln( "Wert = " + 1.0 / n ) ;
}
(62)
Schleifen - wann welche verwenden ?
1. Anzahl der Wiederholungen steht von Anfang an fest oder kann berechnet werden :
⇒ for-Schleife verwenden :
Bsp:
int n = IO.promptAndReadInt ( "Anzahl Durchläufe : " ) ;
for( int i=1; i<=n; i++ ) { /* etwas tun */ }
2. Erst während Durchläufen wird über weitere Fortsetzung entschieden :
⇒ while- oder do ... while-Schleife verwenden :
Bsp:
char c = IO.promptAndReadChar( "Aktion ausführen? (j/n) " ) ;
while( c == ' j ' ) {
// etwas tun ......
c = IO.promptAndReadChar( "Nochmal (j/n) ? " ) ;
}
3. Aber: Prinzipiell jede for-Schleife auch durch while-Schleife ausdrückbar !
Bsp:
int n = IO.promptAndReadInt( "Anzahl Durchläufe : " ) ;
while( i <= n ) { /* etwas tun */ ....... i++ ;
int i = 1 ;
}
Jedoch for-Schleife besser verständlich, da alle nötigen Infos im Kopf der for-Schleife
zusammengefasst sind - und nicht über den Schleifenkörper verstreut sind !
© H.Neuendorf
Java-Methoden
(63)
Methodendeklaration :
class Groesstes {
public static void printMax( int x, int y ){ // Methodenkopf
if ( x >y ) IO.writeln(x) ;
else
Methodenkopf { Methodenrumpf }
// Methodenrumpf
Methoden können Parameter-Werte
entgegennehmen oder parameterlos sein
IO.writeln(y) ;
printGruss( ) ;
}
public static void printGruss( ) {
// Methodenkopf
IO.writeln( "Hallo DH" ) ; // Methodenrumpf)
Parameterübergabe : Kopie des aktuellen
Parameters an formalen Parameter ⇒
Typkompatibilität gefordert !
}
public static void main( String[ ] args ) {
int a = 10 ; int b = 20 ;
printMax( a , b ) ;
// Methodenaufruf ...
//.. mit Parametern a und b
printGruss( ) ;
Klassen können beliebig viele Methoden
enthalten - Reihenfolge egal !
// Methodenaufruf ohne Parameter
}
Methoden können im Rumpf andere
Methoden aufrufen →
}
Formale Parameter : in Deklaration angegeben
Aktuelle Parameter : bei Aufruf konkret übergeben
Terme erlaubt : printMax( 10, 2*b-1 ) ;
© H.Neuendorf
Methoden printMax() und printGruss() stehen
auf gleicher Ebene wie die spezielle Methode
main( ) "Hauptprogramm"
Dabei wird Ausführung der aufgerufenen
Methode an Aufrufstelle eingeschoben
Signatur von Methoden
(64)
Methodenkopf
public void printMax( int x, int y )
Methode = Kopf (header) + Rumpf (body)
↑
↑
↑
↑
Methodenrumpf : Anweisungsfolge
1.
2.
3.
4.
Methodenkopf :
Signatur = Schnittstelle ⇒ Aufrufsyntax
→ Kenntnis Methodensignatur befähigt, Methode aufzurufen
1. Sichtbarkeit : legt fest, aus welchem Kontext Methode aufrufbar ist
a) public :
jedes "Programmteil" darf die Methode aufrufen
b) private : Methode von "außen" nicht aufrufbar; nur aus Methoden der selben Klasse aufrufbar
2. Typ Rückgabewert, den Methode bei Aufruf zurückliefert
a) void ("leer") : Methode liefert nichts zurück
b) int, long, float, char, .... :
Methode liefert Wert zurück
3. Methodenname : dadurch verschiedene Methoden einer Klasse unterschieden
4. Parameterliste : Typ + Name der Parameter, die bei Methoden-Aufruf zu initialisieren sind
a) Methoden können mehr als einen Parameter tragen
b) Auch parameterlose Methoden →
(mittes Komma aufzählen)
Aufruf mit leerer Parameterliste printGruss( ) ;
Aufruf von Methoden :
Durch Angabe Namen + Mitgeben korrekter Parameterwerte
© H.Neuendorf
printMax( 51, 10 ) ;
Methoden mit Wertrückgabe
class Groesstes {
(65)
Prozeduren geben keinen Wert zurück
⇒ Rückgabetyp void (kein return nötig)
public static int calcMax( int x, int y ) {
IO.writeln( "Berechnung läuft " ) ;
if( x >y ) return x ; // Rückgabe durch return
else
Funktionen geben einen Ergebniswert zurück
⇒ Rückgabetyp ist im Kopf anzugeben !
return y ;
}
public static void main( String[ ] args ) {
int a = 10 ; int b = 20 ;
int z ;
// Aufruf + Zuweisung des Rückgabewerts an z
z = calcMax( a , b ) ;
calcMax( 2 , 3 ) ; // Verwerfen des Ergebnisses
gruesse( 't' ) ;
}
Müssen mit return-Anweisung abschließen.
Ausführung der return-Anweisung beendet
Methodenaufruf.
Compiler prüft Vorhandensein korrekter returnAnweisung !
Nur ein einziger Rückgabewert möglich
Aber : Auch ganze Objekte !
Funktionen auch quasi prozedural aufrufbar ohne Rückgabewert zu verwenden
public static void gruesse( char c ) {
if ( c == 'a' ) return ;
return-Anweisung in Prozeduren :
IO.writeln( "Hallo" ) ;
Verwendbar, um vorzeitig abzubrechen
}
}
© H.Neuendorf
Anweisung return ;
(ohne Rückgabewert !)
Methoden - Wertrückgabe + Schachtelung
class Groesstes {
public static int calcMax( int x, int y ) {
if( x >y ) return x ;
else
// Rückgabe
return y ;
}
public static void gibAus( int a ) {
(66)
Als Eingabewert zum Aufruf einer
Methode kann direkt ein anderer
Methodenaufruf eingesetzt werden, der
den korrekten Rückgabetyp hat !
Umweg über entsprechend typisierte
Variable ist nicht nötig
IO.writeln( "Wert beträgt: " + a ) ;
⇓
}
public static void main( String[ ] args ) {
Methodenaufrufe können
geschachtelt werden !
gibAus( 56 ) ;
Keine direkte
Trennung von
Deklaration und
Implementierung
möglich !
( → Interfaces )
int a = 10 ; int b = 20 ;
int z = calcMax( a , b ) ;
gibAus( z ) ;
a = 45 ; b = 21 ;
gibAus( calcMax( a, b ) ) ;
}
}
© H.Neuendorf
Bsp: Methode gibAus() muss mit
Integerwert aufgerufen werden :
a) direkte Übergabe des Werts
b) Übergabe Variable, die Wert trägt
c) Aufruf einer Methode, die Wert
zurückliefert
(67)
Finale Methodenparameter
class Kubisch {
public static double hochDrei( final double x ) {
// x = 10.0 ; Fehler !!
double fx = x * x * x ; // ok!
return fx ; // oder: return x * x * x ;
}
public static void main( String[ ] args ) {
double y = hochDrei( 2.75 ) ;
IO.writeln( "Wert = " + y ) ;
}
}
Methoden sollten .....
Finale Methodenparamter dürfen in
Methode verwendet aber nicht im Wert
verändert werden !
Selbstkontrolle der Entwicklerintention
durch Compiler …….
Leitlinien für "gute" Methoden
9 eine einzige klar definierte Aufgabe gut erledigen
9 übersichtlich bleiben – dh nicht zu viele Parameter und nicht zu viel Coding aufweisen
9 nützlich und wiederverwendbar sein – dh nicht zu wenig Coding enthalten
9 ausgewogenen Kompromis zwischen Allgemeinheit und Einfachheit darstellen
9 alle nötigen Daten als Parameter erhalten und nicht von globalen Variablen abhängen
9 Ergebnisse als Rückgabewerte zurückliefern - und Seiteneffekte möglichst vermeiden
9 gut dokumentiert werden
© H.Neuendorf
Rekursion
⇒ Wiederholung ohne Schleifen !
Methoden-Selbstaufruf
↔
Schleifen : Iteration
(68)
Rekursion : Selbstaufuf
FAKULTÄT n! = 1*2*3* ....*(n-1)*n
iterativ
⇒
n! = (n - 1)! * n
rekursiv
Basisfall → n=0: 0! = 1
public static long fak( int n ) {
if ( n==0 ) { return 1; } // Basisfall
else { return n * fak( n-1 ); } // Rekursion auf ( n-1)!
}
Problem auf sich selbst
zurückgeführt + vereinfacht
bis zum trivialen Basisfall
6
Interner Ablauf
fak(3)
fak( 2 ) aufrufen
Rückweg
3 * fak(2)
Wert 3 zwischenspeichern
Zurückgelieferte Werte
mit gespeicherten
Werten multiliziert
2
fak(2)
Rekursionen :
1. Methode muss Basisfall enthalten
2. Rekursion muss sich auf Basisfall zubewegen
3. Basisfall muss erreicht werden
2 * fak(1)
Andernfalls Stack-Overflow
1
else-Zweige
Voraussetzungen :
fak(1)
Jeder rekursive Aufruf von
fak hält einen eigenen
temporären Wert im
Speicher
1 * fak(0)
1
fak(0)
Basisfall :
if-Zweig
© H.Neuendorf
1
Vorteil :
Eleganz
Problem :
Speicherbedarf
Daten aller nichtabgeschlossenen Aufrufe (incl.
Rücksprungadressen) müssen auf Laufzeitstack
zwischengespeichert werden !
Rekursion
(69)
Beispiele
Rekursive Modulo-Definition :
public static int mod( int a, int b ) {
falls a < b
⎧a
mod(a , b) = ⎨
⎩mod(a − b, b) falls a ≥ b
if( a < b ) { return a } // Basisfall
else { return ( mod( a-b, b ) ) ; } // Rekursion
}
Rekursive Exponential-Definition für ganzzahlige Exponenten :
public static double power( double x, int y) {
x y = x ⋅ x y −1
if( y == 0 ) { return 1 } // Basisfall
else { return ( x * power( x, y-1 ) ) ; } // Rekursion
}
⎛ n −1 ⎞
∑ i = ⎜⎜ ∑ i ⎟⎟ + n
⎝ i =0 ⎠
i =0
n
Rekursive Summation von ganzen Zahlen : (statt for-Schleife)
public static int sum( int n ) {
if( n > 0 ) { return (n + sum( n-1 ) ) ; } // Rekursion
else { return 0 ; } // Basisfall
}
© H.Neuendorf
(70)
Rekursion Probleme
n
Hoher Speicherbedarf + zahlreiche Selbstaufrufe
FIBONACCI-Folge → jedes Glied ist Summe der beiden Vorgänger
erste beiden Glieder Wert 1 = Basisfall
public static long fibonacci( int n ) {
if ( n==1 || n == 2)
{ return 1 ; }
// Basisfall
else { return fibonacci( n-1 ) + fibonacci( n-2 ) ; } // Rekursion
}
fibonacci(5)
Es gibt aber auch
intelligentere rekursive
Lösungen …
fibonacci(n)
1
1
2
1
3
2
4
3
5
5
6
8
7
13
8
21
9
34
....................
fibonacci(4)
fibonacci(3)
fibonacci(3)
fibonacci(2)
fibonacci(2)
fibonacci(1)
Durchführung zeigt Ineffektivität :
fibonacci(2)
fibonacci(1)
- Hohe Zahl von Selbstaufrufen
- Zahlreiche Zwischenergebnisse mehrfach berechnet
⇒ Simple Rekursion nicht das geeignete Mittel !
© H.Neuendorf
Lokale + Globale Variablen - Sichtbarkeiten + Lebensdauer
Gültigkeitsbereiche :
class Beispiel {
public static int a = 5 ;
// "global"
public static final double PI = 3.14 ;
public static void tuWas( int x ) {
int y ;
// lokale Variable y
y=a +x;
double d = 1.7 * PI ;
}
public static void main( String[] args ) {
int y = 22 ; // lokal
double d = 2.3 * PI ;
a = 10 ;
tuWas( 7 ) ;
}
}
(71)
Lokale Variablen :
Auf Methodenebene deklariert
Nur dort verwendbar ⇒ Außerhalb Methode nicht
"sichtbar" / nicht verwendbar / nicht existent !
Speicherplatz jedesmal bei Methodenaufruf neu angelegt.
Bei Methodenende Speicherplatz freigegeben + lokaler
Variablenwert gelöscht
⇒ Lokale Variablen "leben" nur während der
Ausführung ihrer Methode
Globale Variablen :
Auf Klassenebene deklariert
Gültig + verwendbar in allen Methoden der Klasse
Speicherplatz angelegt, wenn Programm startet. Erst bei
Programmende Speicherplatz freigegeben. Bis dahin
behält globale Variable ihren Wert
⇒ Globale Variablen der Klasse "leben"
In Java gibt es keine echten globalen Variablen – es
handelt sich um (statische) Attribute der Klasse
© H.Neuendorf
während gesamter Programmausführung
(72)
Blockkonzept : Zugriffsbereiche
class Bloecke {
public static double a = 1.0 ; // global
public static void tuWas( ) {
for( int i = 1 ; i < 10 ; i++ ) {
double d = 9.0 ;
// lokal
d = d + a ; // OK !
for( int j = 1 ; j < 5 ; j++ ) {
// OK : Tiefergeschachtelter Block !
d = d + 1.0 ;
}
IO.writeln( " Wert = " + d ) ; // OK !
}
// Fehler: Zugriff außerhalb Block !
d = d + 2.0 ;
IO.writeln( " Wert = " + d ) ;
}
public static void main( String[] args ) {
tuWas( ) ;
}
}
© H.Neuendorf
Lokale Variablen :
In Methoden-Blöcken deklariert bzw.
in Unterblöcken von Methoden !
Nur innerhalb Block zugreifbar, in dem
sie deklariert wurden + in darin
enthaltenen tiefergeschachtelten
Unter-Blöcken
Lokale Variablen sollten "so spät und eng" wie
möglich angelegt werden - dh nur dort verfügbar sein,
wo sie benötigt werden : Minimal Scope
Variable d "lebt" im Block der zu forSchleife - in der d deklariert wurde.
Auch in darin enthaltenen Unter-Blöcken
angesprechbar.
Jedoch außerhalb "ihres" Blocks nicht
ansprechbar / verwendbar !
(73)
Namensräume : Methoden repräsentieren eigenen Namensraum
class Beispiel {
Namensraum 3
Trotz Namensgleichheit kein Namenskonflikt :
Namensraum 1
public static int tuWas( int para ) {
int x = 10 ;
x = para ;
return x ;
}
Namensraum 2
public static int tuDas( int para ) {
int x = 20 ;
x = para ;
return x ;
}
public static int x = 30 ;
}
Jeder Methode verfügt über eigene Variable x
In Methode: Lokale Variable
→ Nur sichtbar + benutzbar in Methode
→ Außerhalb Methode verborgen
Die gleichnamigen Variablen leben in
verschiedenen Namensräumen
Namen in einem Namensraum unabhängig
von Namen in anderem Namensraum wählbar!
Unzulässig sind Variablen mit gleichem Namen im
selben Namensraum ! Compiler-Fehler !
Block allein genügt nicht :
int x = 1 ;
Regel :
Wird mehrfach vergebener Variablenname
benutzt, wird immer die Variable angesprochen,
in deren Namensraum man sich befindet
© H.Neuendorf
{ int x = 3 ; }
// Fehler !
OK in C++ !
Lokale + Globale Variablen - Sichtbarkeit + Lebensdauer
class Beispiel {
public static int x = 10 ;
public static int y = 20 ;
Sichtbarkeit der globalen Variablen x wird
unterbrochen durch Sichtbarkeitsbereich der lokalen
gleichnamigen Variablen x
public void m ( int par ) {
int x ;
x = par ;
}
Das lokale x verdeckt das gleichnamige globale x
// .................
}
Sichtbarkeit = Programmbereich, in dem auf Variable zugegriffen werden kann :
Von: Deklaration der Variablen
Bis:
Ende des Blocks, in dem Variable deklariert wurde
Variablen innerer Blöcke verdecken gleichnamige Variablen äußerer Blöcke
Gutes Miko-Design :
Minimized Scope →
Lokale Variable sollte nur in den Blöcken sichtbar sein, in dem sie auch wirklich benötigt wird
Beim Deklarieren möglichst auch sinnvoll initialisieren
© H.Neuendorf
⇒
Laufvariable der for-Schleife lebt nur in dieser
⇒
Besser als while-Schleife mit stets externer Variablendeklaration
(74)
(75)
Namenskonventionen in Java-Programmen
Keine Vorschrift - jedoch allgemein üblich !
Einheitlichkeit + Konsistenz erhöht deutlich Lesbarkeit der Programme !
Klassennamen beginnen mit Großbuchstaben
IO, String, Konto
In Klassennamen aus mehreren Worten beginnt jedes Wort mit Großbuchstaben
ZinsUndRatenRechner
Methoden nach Verben benennen
Methodennamen beginnen mit Kleinbuchstaben
writeln()
CamelCase für
zusammengesetzte
Namen
In zusammengesetzten Methodennamen schreibt man Wortanfänge groß
promptAndReadDouble()
Variablennamen beginnen mit Kleinbuchstaben
wert
Konstanten bestehen aus Großbuchstaben MINIMUM = 50
Konstantennamen aus mehreren Worten durch Unterstriche zusammengesetzt
MAX_VALUE = 100
Hilfsvariablen (Schleifenzähler etc) mit kurzen Namen belegen i , j
Methoden die boolean zurückliefern sollten entspr. Frage formen isOpen(), hasNext()
Keine Umlaute (ä,ü,ö,) oder Sonderzeichen (ß, ...) verwenden (trotz UC .....)
© H.Neuendorf
Herunterladen