75
(1) © H.Neuendorf Einführung in die Programmierung mit Java (2. Semester IT + AI) 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 Prof. Dr. Herbert Neuendorf (DH Mosbach) [email protected] (voraussichtliche) Inhalte : … möglichst zügig wegen C

z1.Teil : Grundlegende Konzepte der Java- · PDF fileJava-VMs für relevante Plattformen zur Verfügung gestellt - verstehen alle denselben Bytecode Bytecode Compiler Klassen Editor

Embed Size (px)

Citation preview

(1)

© H.Neuendorf

Einführung in die Programmierung mit Java (2. Semester IT + AI)

1.Teil : Grundlegende Konzepte der Java-ProgrammierungGrundlagen

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

Prof. Dr. Herbert Neuendorf (DH Mosbach) [email protected]

(voraussichtliche) Inhalte :

… möglichst zügig wegen C …

(2)

© H.Neuendorf

Klassen + ObjekteSinn 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 ……….

Arrays – mit primitive Datentypen und Objekten

Zeichenketten (Strings)

Hüllklassen (nur Einführung)

Fortsetzung Inhalte:

(3)

© H.Neuendorf

2.Teil : ObjektorientierungVererbung - 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

Einige Klassen aus Standardpaketen

Enums

Ausnahmebehandlung / Exceptions

Clonen von Objekten

Innere Klassen

Reflection

Fortsetzung Inhalte :

(4)

© H.Neuendorf

3.Teil : DatenstrukturenDynamische Datenstrukturen: Verkettete Listen + Bäume

Aufbau + typische Operationen

Stack + Queue als verkettet Liste

Fortsetzung Inhalte :

3. Semester (Prof. Deck)

Ereignisorientierte Programmierung mit AWT + Swing

Threading

Persistenz

Netzwerk-Prg, RMI, Sockets

Datenströme

Collection Framework

Spezielle Java-Klassen

..............................

Fortsetzung

Je nach verfügbarer Zeit, evtl. eher in Übungen eingebaut …

(5)

© H.Neuendorf

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) → www.dhbw-mosbach.de/index.php?id=1653

Umfassendere Überblicke über Java :... (1000-Seiten Bücher - nicht erforderlich) ...

Ressourcen :java.sun.com Java Homepage von Sun Microsystems

Dort JDK: Popular Downloads → Java SEjava.sun.com/javase/6/docs/ JavaSE 6 Doku

www.java.de Java User Group Deutschland

www.eclipse.org Eclipse-Page mit allen Downloads

Kein Skript kann die Lektüre eines guten Buches ersetzen !!

Literatur

2.Auflage

(6)

© H.Neuendorf

Voraussetzungen : keine ... aber ...

Ablauf …..Vorlesung: Blöcke zu 4-5 Stunden

Praktische Übungen: integriert

Software: SUN JDK 6Eclipse IDE 3.5

Benotetes Programmierprojekt

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 !

(7)

© H.Neuendorf

MaschinenspracheAssembler

Java

C++

C#

Historie der Programmiersprachen

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 .........

James Gosling(Sun)

B. Stroustrup

(8)

© H.Neuendorf

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: WWW1995: 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) NetBeans (Sun) Eclipse .....

Weiterentwicklungen: 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)

(9)

© H.Neuendorf

Java = Sprache + Plattform

Programmiersprache :

"100%" objektorientiert – "alles" in Klassen

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

Plattform :

Fülle von Klassenbibliotheken (Paketen) :Einheitliche Schnittstellen für alle unterstützen Betriebssysteme → Aufrufe durch Laufzeitumgebung für reale Plattform umgesetzt

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

Klassenbibliotheken

Virtuelle Maschine VM

Hardware

Betriebssystem

Editionen :

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)

(Smartphones, ....)

(10)

© H.Neuendorf

Wo "lebt" Java ? → Java-Laufzeitumgebungen

Standalone-Applikationen :

Normale Programme - von Java-VM-Interpreterausgeführt

Applets :

Spezielle Klassen, die in Browser mit integrierter JVM ablaufen - besondere Sicherheitsrestriktionen !

Servlets + JSPs :

Java-Klassen, die auf Webserver dynamisch HTML generieren

Enterprise Java Beans (EJB) :

Services, die ein Enterprise Application Server bereitstellt - u.a. transaktionale Dienste

Varianten :

1. Client JR für Applikationen

2. Webbrowser mit Applets

3. Webserver mit Servlet Container

4. Application Server mit EJB-ContainerAlle nutzen Java-Klassenbibliotheken und werden in Java-VM ausgeführt.

Unterschiede bestehen in Anwendungs-Struktur und Umgebungen, in denen VM arbeitet.

Umgebung: JDK / Java SDK

www.java.sun.com

SUN: Java Development Kit (1.6 = 6)

Laufzeitsystem + Entwicklungstools

JRE: Java Runtime Environment

= nur JVM-Laufzeitbestandteile

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)

© H.Neuendorf

Varianten der Java-Laufzeitumgebung

Java-Anwendung

Klassenbibliotheken

Virtuelle Maschine VM

Hardware

Betriebssystem

Java-Client

Java-Applet

Klassenbibliotheken

Virtuelle Maschine VM

Hardware

Betriebssystem

Webbrowser

Browser-Client

1. Frontend-Bereich: Fat Client, Browser, lokaler Rechner

= ursprünglicher Anwendungsbereich von Java

Java-VM in Browser integriert

(12)

© H.Neuendorf

Varianten der Java-Laufzeitumgebung

Java-Servlet

Klassenbibliotheken

Virtuelle Maschine VM

Hardware

Betriebssystem

Servlet-Container

Webserver

Webserver

Enterprise Java Bean

Bibl. + Dienste

Virtuelle Maschine VM

Hardware

Betriebssystem

EJB-Container

Java-App-Server

2. Backend-Bereich :

Java auf dem Server

+

3. Middleware-Bereich : Kommunikation von Objekten in verteilten Systemen

Frontend-Backend / Backend - DB / … :

Netzwerk, RMI, JDBC, Message Queues, WebServices, .....

(13)

© H.Neuendorf

Java-LaufzeitumgebungKonzeption von Java → Write once - run everywhere

Plattformunabhängigkeit ! Keine Annahmen über Zielhardware oder Betriebssystem !

VM: Zwischenschicht, die BS und Hardware kapselt

"Prozessor", der in Software realisiert wurdea) als Maschine definiert, die eigene Maschinenbefehle interpretiert

(aus Sicht des Java-Programms)

b) setzt Anweisungen in plattformspezifische Anweisungen um

(aus Sicht der Plattform)

⇒ 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, ....

Java-Anwendung

Klassenbibliotheken

Virtuelle Maschine

Hardware

Betriebssystem

Java-Client

(14)

© H.Neuendorf

Java-Laufzeitumgebung

C/C++: Write once - compile everywhere

Java: Write once - run everywhere

C-Compiler für Win

C-Compiler für LinuxQuellcode(s)

Maschinencode für Win

Maschinencode für Linux

Linux

Kompilierte Programmiersprache

Windows

Linux

WindowsJava Compiler

Bytecodemaschinen-unabhängig

Java Quellcode

Java

JVM

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

VM-Infrastruktur

(15)

© H.Neuendorf

Interpretierte Sprachen - Bytecode kompilierte Sprachen

Linux

WindowsJava Compiler

Bytecodemaschinen-unabhängig

Java Quellcode

Java

JVM Interpreter

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 InterpreterLangsamer als reine Compiler (C / C++ )

VM = zusätzliche Schicht zwischen Programm und

Ausführungsplattform ⇒ Kostet Zeit !

(16)

© H.Neuendorf

Bytecode = Maschinensprache der JVM

Linux

WindowsJava Compiler

Bytecodemaschinen-unabhängig

Java Quellcode

Java

JVM Interpreter

Sequenz Opcodes (Maschinenbefehle) für JVMOpcodes haben Nummer + Namen

zB: Opcode 96 = iadd = Addiere zwei IntegerBeispiel :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 Stackiadd ; addiere die beiden Integer-Zahlenistore_2 ; speichere das Ergebnis in der Variablen 2

Werte der Parameter werden in Bytecode übernommen :In Bytecode : 21 1 16 5 96 54 2

iload 1 bipush 5 iadd istore 2

JVM Spezifikation : > 150 Instruction Opcodes

Analyse mit JDK-Tool javap Optionen : javap –help ↵Ausgabe Opcodes : javap –c –private nameClassFile ↵

(17)

© H.Neuendorf

JVM-Anatomie

Besonderer Aspekt : Sicherheit

Bsp: Appletcode

Class File Verifier

Byte Code Verifier

Security Manager Betriebssystem

Native Methods

Class Files

Standard Java Klassen

Garbage Collector(Heap)

Execution Engine

Dynamischer Class Loader

+Class File

Verifier+

Byte Code Verifier

Native MethodLinker

SecurityManager

Java Runtime System

(18)

© H.Neuendorf

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 (DLLs, libs)

Security Manager : - 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 .......... )

(19)

© H.Neuendorf

Weiterentwicklung der Java VM : Java Hot Spot VM

Schlechte Performance

Java Bytecode

JVM Runtime

Java Interpreter

Gute Performance

Bytecode wiederholt auszuführender Programmteile (hot spots) wird zur Laufzeit vor Ausführung einmal in

Maschinensprache (Prozessorbefehle) übersetzt :

Java Hot Spot VM

JIT CompilerJust In Time Compilation

Java Bytecode

JVM Runtime

JDK 1.4 (2002)

Java Hot Spot VM von Sun in zwei Versionen ausgeliefert :

Server VM und Client VM/jre/bin/client/ …

/jre/bin/server/ …

mit unterschiedlich optimiertem Start- und Ausführungsverhalten

(20)

© H.Neuendorf

Warum Java ?

“Java: A simple, object-oriented, distributed, interpreted, robust, secure,

architecture neutral, portable, high-performance, multithreaded,

and dynamic language ... ” (Sun: The JavaLanguage – White Paper)

einfach: 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

(21)

© H.Neuendorf

Programmerstelluung - kompilierte Sprachen (Java ist anders !)

Übersetzen + Ausführen :

Vorteil → hohe Geschwindigkeit + Compiler checkt Programm vor(!) Ausführung auf Fehlerfreiheit

Erfassen des Programms : Coding in Quellcodedatei

Ausführen des Programms : Maschinensprache in Binärdatei

BS

Executable

Eingabedaten Ausgabedaten

Library Manager

LinkerObjektmodul Library

Editor

Compiler

Quellcode Fehler-meldungen

(Bsp: C++)

⇒ 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“ ..........

(22)

© H.Neuendorf

Übersetzen + Interpretieren in Java

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

Bytecode

CompilerKlassen

EditorQuellcode

Fehlermeldungen

Interpreter

Java-VM

Eingabedaten Ausgabedaten

Paket

Bytecode von Klassen

BS

Hardware

Systemaufrufe Maschinensprache

Vorteil :Plattformunabhängigkeit BytecodeBytecode deutlich effizienter interpretiert als reiner ProgrammcodePrüfungen bei Compilierung + bei Ausführung durch JVM⇒ Vorteile Interpreter + Compiler kombiniertNachteil :Benötigte Klassendateien einzeln von JVM einzulesen = zeitaufwendig

Übersetzungseinheit in Java ist die Klasse

JDK-Compiler ist javac

*.java

*.class

(23)

© H.Neuendorf

Erstellen + Ausführen von Java-Programmen

Test.java

Test.class

(Bytecode)

javac

Compile-Zeit

Lauf-Zeit

Interpreter javaJVM

Hardware

Class Loader

Class File VerifierByte Code Verifier

Lokaler PCNetzwerkInternet

PC

PC / Webbrowser

Applikation /

Applet-Klassen + HTML

Benutzte Klassen (class-Files) können an unterschiedlichen Orten liegen.

Erst zur Laufzeit bei Bedarf nachgeladen !

Für jede im .java-Fileenthaltene Klasse wird eigenes .class-Filevom Compiler generiert

Durch java ausgeführte Datei muss main() -Methode enthalten ...........

(24)

© H.Neuendorf

Erstellen + Ausführen von Java Programmen

JDK: Java Development Kit

Compiler + InterpreterWerden aus Kommandozeile

aufgerufen z.B. :

C:\ Demos > javac Test.java

C:\ Demos > java Test

QuelldodeTest.java

EditorPC

Java Compilerjavac.exe

BytecodeTest.class

Internet

EingabeJava Bytecode

Interpreterjava.exe

Browser

Ausgabe

Lokaler PCNetzwerkInternet

Hardware

Compile-Zeit

Lauf-ZeitJVM

Verwendung fremder Klassen :

Weitegabe kompilierter class-Files ohne Quellcode genügt !

(25)

© H.Neuendorf

Java-Werkzeuge - Java Development Kit (JDK)Kommandozeile :

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

SET CLASSPATH=.;C:\MyFolder

javac Compilerjava JVM-Launcherappletviewer Darsteller für Appletsjavadoc Dokumentationswerkzeugjar Archivierung (Zusammenfassung von Files)javap Bytecode-Analyse......... ............................ (vieles mehr ...)

Kein statischer Linker da Java-Laufzeitsystem benötigte Klassen dynamisch bei Bedarf zur Laufzeit lädt durch Class Loader

Integrierte Entwicklungsumgebung (IDE) → Eclipse :

Massive Unterstützung bei Erstellung, Verwaltung, Bearbeitung und Ausführung von Programmierprojekten ( Projektdarstellung, Wizzards, Debugger, Syntax-Colouring, ..... )

Beispiel.java

Bytecode

javaProgrammtext

javac

Entwickler

Übersetzen

Ergebnis

Beispiel.class

Interpretieren + Ausführen

Editor

(26)

© H.Neuendorf

Struktur Programmiersprache

Sprachdefinition: Sun → Java Language SpecificationFester Wortschatz : Schlüsselwörter = reservierte WörterNeue Bezeichner : Benutzerdefinierte Namen mittels zulässigem ZeichensatzZeichensatz : Klein-/ Großbuchstaben in Java NICHT austauschbar! Case Sensitive !!!

Syntax: Regelt Bildung sinvoller Anweisungen aus Zeichen und reservierten Wörtern

Syntaxregeln = Metasprache (Backus-Naur-Form BNF-Syntax)Ziffer ::= 0|1|2 |3 |4 |5 |6 |7 |8 |9Zahl::= Ziffer { Ziffer }Kleinbuchstabe::= a|b|c|d|e|f| .......Großbuchstabe::= A|B|C|D|E|F| .......Buchstabe::= Kleinbuchstabe | GroßbuchstabeBezeichner::= Buchstabe { Buchstabe | Ziffer }

Sematik: Bedeutung der einzelnen Sprachkonstrukte = Wirkung der Programmanweisungen

" Was bedeuten die Sätze der Sprache im jeweiligen Kontext? "

"Syntaktische Ableitung"

ZifferSyntaxdiagramm für " Zahl "

(27)

© H.Neuendorf

Grundkonzepte von Programmiersprachen

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

Ausdrücke :

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

Zunehmende K

omplexität

(28)

© H.Neuendorf

Elementare Bestandteile von JavaA.) Elementare Symbole :Namen : Bezeichnen Variablen, Konstanten, Typen, Methoden, Klassen, ....

Bestehen nur aus Buchstaben, Ziffern, ‘_‘ und ‘$‘ Nicht ' , # * ....

Erstes Zeichen muss Buchstabe, ‘_‘ oder ‘$‘ sein (keine Leerzeichen !)

Groß- und Kleinbuchstaben unterschieden - Case Sensitive ! (Variable min ≠ Min)

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 Kleinbuchstabenabstract 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 newnull 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 (für 10,11,...,15)→ Kennzeichnung durch 0x Bsp : 0x1A = 16+10 = 26

c) Oktal = Ziffern 0 ..... 7 → Kennzeichnung durch 0 Bsp : 012 = 8+2=10

Gleitkommazahlen : verschiedene Darstellungsweisen Kommateil mit Punkt !

Bsp : 3.2 3. 0.3E1 3E-1 3.2f 3.2F 3.2d 3.2D

(29)

© H.Neuendorf

Java-Schlüsselwörter - Kategorien

Java Schlüsselwörter

Klassen / Objecte Modifizierer Elementare Datentypen Fehlerbehandlung

classinterfacenewextendsimplementsinstanceof return

privatepublicprotectedabstractfinalnativestatic strictfpsynchronizedtransientvolatile

byteshortintlongfloatdoublebooleanchar

trycatchthrowsthrowfinallyassert

Schleifen Bedingungen Packages Referenzen/ Konstanten

dowhileforbreakcontinue

ifelseswitchcasedefault

packageimport

thissupervoidnulltruefalse

(30)

© H.Neuendorf

Einfache Elemente von JavaA) 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 überschreitenBsp: "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 belegtNamenszweideutigkeiten sind unzulässigAufzä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 erhaltenBsp: 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 !

(31)

© H.Neuendorf

B.) Variablendeklaration :

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: 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

8 Bits = 1 Byte

(32)

© H.Neuendorf

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 darstellbaraber : Genauigkeit prinzipiell begrenzt ⇒ Rundungsfehler !

Wichtig bei Vergleichsoperationen !!

Teilmengenbeziehung : double ⊃ float " ⊃ " long ⊃ int ⊃ short ⊃ byteBsp: double d = 1.0; float f = 2.0f; int i = 3;

f = i ; // oki = f ; // Fehler !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

Typregeln in Ausdrücken beim "Mischen" der Zahlentypen :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 !

double d = 1.0; float f = 1.0f;

int i = 2; short s = 3;

... f + i .... // float

... d * i .... // double

... s + s .... // int !!

... f / 3 .... // float

... (float) i / 3 .... // float

Rechnen mit Gleitkommazahlen für Rechner aufwändiger als mit ganzen Zahlen !

(33)

© H.Neuendorf

Standard-Datentypen

b) Gleitkommazahlen: float 32-Bit double 64-BitIntern 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

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 Genauigkeitdouble → 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: 1.0 2.56f 4.45e-11 2.2E9f ...... ( E oder e bedeutet 10 hoch )

Aufgrund exponentieller Zahlendarstellungkö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 !

(34)

© H.Neuendorf

Standard-Datentypen : 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 geschlossenBei Überschreiten positiven Bereichs → Wiedereintritt in negativen BereichBsp: 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) ; // ok!

(35)

© H.Neuendorf

Fließkommazahlen :1. Default double ! ⇒ 1 + 1.0 ist double, 1 + 1.0f ist float

Bsp: float f = 1 + 1.0 ; // Fehler !2. Rundung von Ganzzahlen auch bei Zuweisung zu Fließkommatypen !

⇒ double d = 1 / 2 ; // in d 0.0 ! 1 und 2 als Ganzzahlendouble d = 1.0 / 2 ; // in d 0.5 1.0 als double-Zahldouble d = (double) 1 / 2 ; // in d 0.5 1 zu double gecastetdouble d = 0.8 + 1 / 2 ; // in d 0.8 ! 1/2 liefert 0

3. Fließkomma-Berechnungen sind ungenau !double d = 1.03 – 0.42 ; // in d steht 0.6100000000000001

Casting : → Castoperator : ( type ) x explizite Typkonvertierung1. Zuweisung an größeren Datentyp unproblematisch

Bsp: int i = 17; float f = i ; // ok – 17.0f implizite automatische Typkonvertierung2. 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 !

..... Kleine Fallen

Somit Fließkommatypen im Grunde ungeeignet für monetäre Berechnungen !!

(36)

© H.Neuendorf

Standard-Datentypen ..c) Zeichen = Typ char : Codierung mit 16bit = UC

Einzelnes Zeichen (≠ Zeichenkette) → in einfachen Hochkommata ' 'char ch1 = 'a' ;

Java-Codierung 16bit = 2 Byte-Unicode⇒ char auch "zahlenartig" aber ≠ short-Bereich

double ⊃ float ⊃ long ⊃ int "⊃ char ⊃" short ⊃ byte⇒ Berechnungen : int n = 'c' - 'a'; // n-Wert 2. Zwei Plätze weiter in UC-Tabelle

int k = 'a'; // k-Wert 97short 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 : ASCII : 1 Zeichen = 1 Byte ⇒ 256 ZeichenUnicode : 1 Zeichen = 2 Byte ⇒ 65536 Zeichen ! ← Java

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 ; s2 = 10 + 10 + " Alter" ; // Inhalt: 20 Alter

Erste Zeichen von UC entsprechen den ASCII-Zeichen

char-Variablen könnenZahlenwerte [0 ; 65535]direkt zugewiesen werden –aber keine Werte < 0.

Zuweisung von Ganzzahl-Variablen nur mittels Cast

Bedeutung : Zeichen am Platz in UC-Tabelle

(37)

© H.Neuendorf

Java-Datentypen

ReferenztypenPrimitive Datentypen

Ganzzahltypen :byteshortintlongFließkommatypen :floatdoubleboolsche Werte :booleanZeichen :char

Arrays

Menge von Objekten oder primitiven Datentypen

null

Null-Referenz Klassen / IF

Objektreferenzen

Datentypen

Typ Länge Wertbereich Initialisierung / Default *)

byte 8 Bit -128.....127 (byte) 0

short 16 Bit -32768......32767 (short) 0

int 32 Bit -2147483648....2147483647 0

long 64 Bit < Bereich ± 2^64 > 0L

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

boolean true / false false

char 16 Bit Unicode ! '\u0000' = (char) 0

Elementare Datentypen

Objekttypen

*) Defaults zB wirksam bei Initialisierung von Objekt-Attributen und Array-Inhalten …

(38)

© H.Neuendorf

C) Ausdrücke : Zuweisungen, Operationen :

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; byte b = 4 ;

i = j ; // ok i = s ; // ok s = i ; // Fehler! i = 300 ; // ok b = 300 ; // Fehler!

Konstanten-Deklaration : final int MAX = 527 ; // Schlüsselwort finalDefinition von Konstanten : 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

Elementare Sprachkonstrukte

Jede Art von Anweisung in Java endet mit einem Semikolon ;(Deklaration, Zuweisung, Methodenaufruf, Objekterzeugung ....)

Durch Compiler gecheckt !

(39)

© H.Neuendorf

Elementare SprachkonstrukteZuweisungen und Operationen :

Arithmetische Ausdrücke : 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 - → "binden" am stärksten ........

Bsp: 4 + - 3 // liefert 1 - 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 4 % 3 = 1 -7 % 2 = -1

bei Gleitkommazahlen: ( selten verwendet ......)

Gleitkomma-Divisionsrest von x/y

8.5 % 2.1 = 8.5 - 4 * 2.1 = 0.1 Divisionsrest

Bei Ganzzahltypen ist /0und %0 nicht zulässig und liefert zur LZ ArithmeticException

(40)

© H.Neuendorf

Arithmetik1. 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 // nicht direkt zuweisbar, aber mittels Hüllklassen

double d = 0.0 / 0.0 // in d steht NaN !

float f = 1.0f / 0f // in f steht infinty !

double g = 5. % 0 // in g steht NaN !

Weiterverarbeitung "pathologischer" Werte mittels Hüllklassen (s.u.)

3. Strenge und nichtstrenge Gleitkomma-Arithmetik strictfpBezieht 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

anwendbar auf Klassen, Interfaces, einzelne Methoden

(41)

© H.Neuendorf

Arithmetische Ausdrücke : 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

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 : x = (T) ( x op (y) ) ;

int x += y; // x = (int)(x + (y) );

x /= y; x -= y; x %= y; x *= y;

…. auch für alle anderen arithmetischen, logischen und Bit-Operatoren

Präfixform ++x : Erst x manipulieren, dann weiterrechen

Postfixform x-- : Erst Zuweisung durchführen, dann x manipulieren

Bsp: short a *= b+1; // a = (short)( a*(b+1) );

In besonderen Fällen schnellere Auswertung

(42)

© H.Neuendorf

Operatorene) Bitoperationen (~, &, |, ^, <<, >>, >>>) nur für Ganzzahltypen – und char

Verändern Bitmuster : Direkte Manipulation der Bits in Binärdarstellung

⇒ Liefern geändertes Bitmuster zurück

Negation :a ~a0 1

1 0

Und, Oder, Exclusiv-Oder :a b a & b a | b a ^ b0 0 0 0 0

0 1 0 1 1

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 = 0110 ⇒ (a << 1) liefert 1100

a >> b Schiebt Bits von a um b Stellen nach rechts und füllt mit höchstem Bit von a auf

Bsp: a = 1100 ⇒ (a >> 2) liefert 1111

a >>> b Schiebt Bits von a um b Stellen nach rechts und füllt 0-Bit auf

Bsp: a = 1100 ⇒ (a >>> 2) liefert 0011

(43)

© H.Neuendorf

Bitoperatoren

Negation : ~byte b = 3 ; // ≡ 0000 0011byte c = ~b ; // ≡ 1111 1100 ≡ - 4// Wert von c ist - 4 !

Addition : &byte b1 = 3 ; // ≡ 0000 0011byte b2 = 1 ; // ≡ 0000 0001bye c = b1 & b2 ; // ≡ 0000 0001 ≡ +1 ;// Wert von c ist +1 !

Shift : Linksshift << und Rechtsshift >>byte b = 2 ; // ≡ 0000 0010byte c = (b << 1) ; // ≡ 0000 0100 ≡ +4// Wert von c ist +4 !

Bsp: Zahldarstellung mit fiktiven 4 bits im Zweierkomplement

Höchstes Bit → Vorzeichen !

1 = - 23 0 = + 0

Dezimal Bitmuster+8 nicht darstellbar+7 0111+6 0110+5 0101+4 0100+3 0011+2 0010+1 00010 0000-1 1111-2 1110-3 1101-4 1100-5 1011-6 1010-7 1001-8 1000Schieben von Bits nach links bzw rechts entspricht

Multiplikation bzw Division durch 2 ......

(44)

© H.Neuendorf

Java-OperatorenOperatoren

mathematisch logisch Vergleiche Zuweisung

Addition +Subtraktion -Multiplikation *Division /Modulo %Vorzeichen + -Inkrement ++Dekrement - -

Negation !Konj. && &Disj. || | ^

Gleichheit ==Ungleich !=Größen < >

<= >=Referenz instanceof

Zuweisung =+= -= *= .............

bitweise

Negation ~und &oder |xor ^Shift >>,<<,

>>>

Auswertregeln :→ von links nach rechts

→ gemäß Vorrangregeln

- "Punkt vor Strich"

- Klammern höchste Priorität

⇒ Im Zweifel Klammern setzen !Besonderheit : Zuweisungsoperator =x = y = z ausgewertet als x = ( y = z )

Für boolesche Ausdrücke

(45)

© H.Neuendorf

Priorität der Operatoren - Vorrangregeln

Zusammengesetzter Ausdruck : boolean b = 4 + 3 < 7 * 2 - 3 ; // liefert trueAusführungsreihenfolge der Operationen durch Priorität der Operatoren geregelt Im Zweifel + zur Übersicht Klammern setzen !

Bezeichnung OperatorUnäre Operatoren ++ -- + - ~ !Expliziter Cast ( <type> )Multiplikative Operatoren * / %Additive Operatoren + -Schiebeoperatoren << >> >>>Vergleichsoperatoren < > <= >=Vergleichsoperatoren == !=bitweise Und &bitweise XOR ^bitweise Oder |logisches Und && &logisches Oder || |Zuweisungsoperator = += -= .....

Operation mit höherer Priorität vor Operation niedrigerer Priorität ausgeführtBsp : Punkt- vor Strichrechnung

Setzen von Klammern ändert Auswertreihenfolge !boolean b = 4+3 < 7 * (2 - 3);

// liefert nun false!

hoch

niedrig

(46)

© H.Neuendorf

Grundstruktur Java

Minimales ausführbares Programm :

class Name {

public static void main ( String[ ] args ) {

// ..... Deklarationen .....

// ..... Anweisungen ......

}

}

Schlüsselwort class : Java-Programm stellt selbst Klasse dar

Start des Programms mit Ausführung der zentralen Methode main()

String[ ] args : String-Array, das bei Programm-Aufruf gefüllt werden kann

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

class Hallo { // erstes Programm

public static void main (String[ ] args) {

String gruesse = "Hello World" ;

IO.writeln( gruesse ) ;

}

}

1. Speichern als gleichnamige Datei Hallo.java2. Wechsel ins Quellverzeichnis

3. Aufruf JDK-Compiler : javac Hallo.java4. Ergebnis / Compilat : Hallo.class

5. Ausführen durch Aufruf JVM : java Hallo

Quelldatei hat gleichen Namen wie die Klasse + Extension .java

Zu jeder geöffneten Klammer (Blockanfang) gehört auch eine schließende Klammer (Blockende)

(47)

© H.Neuendorf

Grundstruktur JavaIn Java-Programmen kollaborieren Klassen bzw. Objekte

Objekten werden Aufträge erteilt :

Hallo ruft Methode writeln() der Klasse IO auf

Hallo = Auftraggeber Client

IO = Auftragnehmer ServerKlasse IO stellt Methoden zur Verfg. (s.u.)

Methoden können Parameter haben oder parameterlos arbeiten.

Methoden können Werte zurückliefern.

Durch Semikolon wird Anweisung abgeschlossen ;

// Erstes Programm

class Hallo {

public static void main( String[ ] args ) {

String gruesse = "Hello World" ; // Text

IO.writeln( gruesse ) ; // Methodenaufruf

}

}

Aufrufsyntax :

Objektname.Methodenname( Parameterliste ) ;

writeln(..)Hallo IO

Kollaborationsdiagramm (UML)

Paar von geschweiften Klammern { } mit null oder mehr Anweisungen = Block

Blöcke können geschachtelt werden

Ein Block kann überall da stehen, wo eine einzelne Anweisung verwendet werden kann - da ein Block eine (zusammengesetzte) Anweisung ist

(48)

© H.Neuendorf

Ein- / Ausgabe (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. javaDeren 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 ) ;

}}

Tool-Klasse IO :

Methoden sind public + static

Können direkt ohne Instanziierung in verwendet werden !

(49)

© H.Neuendorf

Konsolen-Eingabe / -Ausgabe mittels IO.javaAusgaben :

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

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 ) double round( double d, int n ) // liefert gerundete float- bzw double-Zahl

... und noch einige mehr ....

(50)

© H.Neuendorf

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 ........

(51)

© H.Neuendorf

Kontrollstrukturen - Verzweigungen + SchleifenA) 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

Aufspaltung in zwei Zweige : Bedingung wahr ⇒ if-Zweig 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 ; IO.writeln (x) ; }

else { x = x - 1 ; IO.writeln (x) ; }

Dangling else : Verschachtelte if-Anweisungen - ein else "hängt in der Luft" :

if ( a < b )

if ( a > 0 ) test = a ;

else test = b ; // auf welches if bezieht sich dieses else ??

Regel : Ein else gehört immer zum direkt vorausgehenden if

(52)

© H.Neuendorf

Datentyp boolean : Nur Werte true und false ( ≠ 0,1 ! ≠ 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 x == 3 ( nicht : x = 3 ; Zuweisung, kein Vergleich ! )!= ungleich x != y> größer x > y < kleiner x < y>= größer oder gleich x >= y<= kleiner oder gleich x <= y

Verknüpfung von Booleschen Termen durch Operatoren :

And: x && y (bzw &) Or : x || y (bzw | ) XOR : X ^ Y (entweder oder) Not: ! X

if ( 0 <= x && x <= 10 || 100 <= x && x <= 110 ) { y = x ; }

if ( ! ( x < 10) ) { x = 20 ; }

Vorrangregel : Im Zweifel Klammern setzen ............... !

== bindet stärker als ! bindet stärker als && bindet stärker als ||

a && b == c && d hat Bedeutung von a && (b == c ) && d

Prüfung gegen NaN-Werte liefert immer false

(53)

© H.Neuendorf

Kurzschlussauswertung : lazy evaluationOptimierungsleistung 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

Bsp: if ( y == 0 && ++x / y > 10 ) ...... // Wenn y != 0, dann ++x / y nicht berechnet !

if ( x < 0 || --x / y < 10 ) ...... // Wenn x < 0, dann --x / y nicht berechnet !

a b a && b a || b a^bw w w w f

f w f w w

w f f w w

f f f f f

a && b

a b

a || b

a

b

Umgehung Kurzschlussaus-wertung durch Operatoren &(statt &&) bzw |(statt || )Bei Operanden-Typ boolean wirken & und |als logische Operatoren, nicht als Bit-Operator

Ternärer Operator : int a = 10; int b = 1; int c = a > 5 ? 2*b : 3*b ;

(54)

© H.Neuendorf

// Ausführlich :char antwort = IO.promptAndReadChar( "Springt Auto an? ( j/n )" ) ; // Abfrage

if ( antwort == ' j' ) { IO.writeln( "prima!" ) ; }else { IO.writeln( "schlecht!" ) ; }

Prinzip :

Abfrage wird in Bedingung der Verzweigung eingebettetAbfrage zuerst ausgewertet → liefert Wert zurück, der dann für Vergleich zur Vfg. steht

Kompakte Entscheidungsabfragen

// Kompakte Formulierung : Zusammenfassung von Abfrage + Bedingungsprüfungif ( IO.promptAndReadChar("Springt Auto an? ") == ' j ' ) {

IO.writeln( "prima!" ) ; }else { IO.writeln( "schlecht!" ) ; }

// Zugleich Initialisierung Variable zur weiteren Verwendungchar antwort ;if ( (antwort = IO.promptAndReadChar("Springt Auto an? ") ) == ' j ' ) { /* … */ }// Verwendung von antwort ……

(55)

© H.Neuendorf

Kontrollstrukturen : switch -Anweisung Mehrweg-Verzweigung

Wert-Prüfung eines ganzzahligen Ausdrucks vom Typ int, short, byte oder char →Davon abhängig wird verzeigt :

int month ; int days ;month = IO.promptAndReadInt( "Monats-Nummer = " ) ;switch( month ) { // dürfte auch zusammengesetzt sein

// Case-Marker mit möglichen Alternativencase 1: case 3 : case 5 : case 7 : case 8 : case 10 : case 12 :

days = 31; // wenn Alternative zutrifft, wird Anweisung ausgeführt break ; // wichtig: damit switch verlassen wird !

// sonst : folgende Anweisungen auch ausgeführt ! case 4 : case 6 : case 9 : case 11 :

days = 30; break ;case 2 :

days = 28; break ;default : // optionaler Default-Zweig - ausgeführt, wenn kein anderer zutrifft

IO.writeln( "Kein gültiger Wert!" ) ;}

Vergleich mit if-Sequenzen : Lesbarkeit + Effizienz !

Lesbarkeit: case gegenüber switch-Anweisung eingerückt. Zugehörige Befehle werden nochmals eingerückt

Es kann nur höchstens einen default-Zweig gebenWenn kein Fall zutrifft und kein default-Fall angegeben, bleibt switch-Anweisung ohne Wirkung

Jeder einzelne case-Fall muss eindeutig sein !!Auch negative ganzzahlige Werte erlaubt

Muss mit case-Labelbeginnen ….

(56)

© H.Neuendorf

switch ( <Ausdruck> ) {case <Konstante> :

<Anweisung>// .................<Anweisung>break ;

case <Konstante> :<Anweisung>// .................

<Anweisung>break ;

default : <Anweisung>// .................<Anweisung>

}

Ausdruck : Mit ganzzahligem Wert vom Typ int, short, byte oder char - nicht aber Typ long !

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" );

}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 ;default : return 500 ;

}}

switch –Anweisung :

Sonderformen :

In jeden case sind auch weitere Fallunterscheidungen oder Schleifen einbaubar. Wird rasch unübersichtlich !

(57)

© H.Neuendorf

B) Schleifen Wiederholte Ausführung von Anweisungsfolgen

while - Schleife 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 ; int n = 5 ; while( i <= n ) { // 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 !

Kontrollstrukturen

(58)

© H.Neuendorf

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 ) ; // wenn i = 5 wird Schleife verlassen

IO.writeln( sum ) ; // hier wird Programm nach Verlassen der Schleife fortgesetzt

Kontrollstrukturen

Anm: do{ anweisungen } while( !bedingung )entspricht dem Konstrukt do ... until anderer Sprachen

(59)

© H.Neuendorf

Kontrollstrukturenfor - Schleife ZählschleifeAnzahl Durchläufe steht fest. Anzahl Durchläufe durch Laufvariable gezählt.

Dreiteiliger Schleifen-Kopf :

for ( <In>; <Fb>; <V> ) { <Anweisungen> }a) Initialisierungsteil : legt Startwert der Laufvariablen fest

b) Fortsetzungsbedingung : wird jedesmal vor Betreten der Schleife geprüft wie while-Schleife !

c) Veränderungssteil : wird nach jedem Durchlauf ausgeführt → verändert Laufvariablenwert

int sum = 0 ; int n = 6 ;

for( int i=1; i <= n; i++ ) {

sum = sum + 1 ;

IO.writeln( "Durchlauf Nr. " + i ) ;

}

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 ; i <= n ; i++ , sum2 = sum2 + 2 ) { /* ... */ }

// chars in UC-Tabelle angeordnet :for( char n='A'; n <='Z'; n++ ) {

IO.writeln( "Hier : " + n ) ;}

Verschieden typisierte Laufvariablen müssten außerhalb for-Schleife deklariert werden

(60)

© H.Neuendorf

Kontrollstrukturenfor - SchleifeSchleife 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 : Rumpf einer Schleife kann wieder Schleife enthalten

// Multiplikationstabelle :

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( );

}// i = 100 ; j = 50 ; Fehler !!

Endlosschleifen :for ( ; ; ) {....} while (true) {.....}Die im Schleifenkopf deklarierte Lauf-

variable ist nur innerhalb Schleife gültig

Jeder Teil des for-Schleifenkopfs darf weggelassen werden :

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 ) ; }

(61)

© H.Neuendorf

Kontrollstrukturen break + continue

Strukturierte Schleifenabbrüche durch break-Anweisung : Kein gotoAbbruch 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 ; int z = 100 ;while( true ) {

sum = sum + z ; 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 */ }

}

Sprünge aus while-, do-, for-Schleifen :

break → direkt hinter Schleifenende

continue → Abbruch aktueller Schleifen-durchgang + Sprung zur Wiederholungs-bedingung der Schleife + Fortsetzung mit nächstem Durchgang

// Verwendung continue :for( int n=-10; n<=10; n++ ) { if( n == 0 ) { continue ; } IO.writeln( "Wert = " + 1.0 / n ) ; }

(62)

© H.Neuendorf

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 : " ) ; int i = 1 ;

while( i <= n ) { /* etwas tun */ ....... i++ ; }

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 !

(63)

© H.Neuendorf

Java-Methoden

Methoden können Parameter-Werte entgegennehmen oder parameterlos sein

Parameterübergabe : Kopie des aktuellen Parameters an formalen Parameter ⇒Typkompatibilität gefordert !

Methoden printMax() und printGruss() stehen auf gleicher Ebene wie die spezielle Methode main( ) "Hauptprogramm"

Klassen können beliebig viele Methoden enthalten - Reihenfolge egal !

Methoden können im Rumpf andere Methoden aufrufen →

Dabei wird Ausführung der aufgerufenen Methode an Aufrufstelle eingeschoben

class Groesstes {

public static void printMax( int x, int y ){ // Methodenkopf

if ( x >y ) IO.writeln(x) ; // Methodenrumpf

else IO.writeln(y) ;

printGruss( ) ;

}

public static void printGruss( ) { // Methodenkopf

IO.writeln( "Hallo DH" ) ; // Methodenrumpf)

}

public static void main( String[ ] args ) {

int a = 10 ; int b = 20 ;

printMax( a , b ) ; // Methodenaufruf ...

//.. mit Parametern a und b

printGruss( ) ; // Methodenaufruf ohne Parameter

}

}

Methodendeklaration :

Methodenkopf { Methodenrumpf }

Formale Parameter : in Deklaration angegeben

Aktuelle Parameter : bei Aufruf konkret übergeben

Terme erlaubt : printMax( 10, 2*b-1 ) ;

(64)

© H.Neuendorf

Signatur von Methoden Methodenkopf

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 (mittes Komma aufzählen)

b) Auch parameterlose Methoden → Aufruf mit leerer Parameterliste printGruss( ) ;

Aufruf von Methoden :Durch Angabe Namen + Mitgeben korrekter Parameterwerte printMax( 51, 10 ) ;

public void printMax( int x, int y )

↑ ↑ ↑ ↑

1. 2. 3. 4.

Methode = Kopf (header) + Rumpf (body)

Methodenrumpf : Anweisungsfolge

(65)

© H.Neuendorf

Methoden mit WertrückgabeProzeduren geben keinen Wert zurück ⇒ Rückgabetyp void (kein return nötig)

Funktionen geben einen Ergebniswert zurück ⇒ Rückgabetyp ist im Kopf anzugeben !

Müssen mit return-Anweisung abschließen. Ausführung der return-Anweisung beendet Methodenaufruf.

Compiler prüft Vorhandensein korrekter return-Anweisung !

Nur ein einziger Rückgabewert möglich Aber : Auch ganze Objekte !

Funktionen auch quasi prozedural aufrufbar -ohne Rückgabewert zu verwenden

return-Anweisung in Prozeduren :

Verwendbar, um vorzeitig abzubrechen

Anweisung return ; (ohne Rückgabewert !)

class Groesstes {

public static int calcMax( int x, int y ) {

IO.writeln( "Berechnung läuft " ) ;

if( x >y ) return x ; // Rückgabe durch return

else 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' ) ;

}

public static void gruesse( char c ) {

if ( c == 'a' ) return ;

IO.writeln( "Hallo" ) ;

}

}

(66)

© H.Neuendorf

Methoden - Wertrückgabe + Schachtelung

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

Methodenaufrufe können geschachtelt werden !

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

class Groesstes {public static int calcMax( int x, int y ) {

if( x >y ) return x ; // Rückgabeelse return y ;

}public static void gibAus( int a ) {

IO.writeln( "Wert beträgt: " + a ) ;}

public static void main( String[ ] args ) {gibAus( 56 ) ;int a = 10 ; int b = 20 ; int z = calcMax( a , b ) ;

gibAus( z ) ;

a = 45 ; b = 21 ;gibAus( calcMax( a, b ) ) ;

}}

Keine direkte Trennung von Deklaration und Implementierung möglich !

( → Interfaces )

(67)

© H.Neuendorf

Finale Methodenparameter

Finale Methodenparamter dürfen in Methode verwendet aber nicht im Wert verändert werden !

Selbstkontrolle der Entwicklerintention durch Compiler …….

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 ..... Leitlinien für "gute" Methodeneine einzige klar definierte Aufgabe gut erledigen

übersichtlich bleiben – dh nicht zu viele Parameter und nicht zu viel Coding aufweisen

nützlich und wiederverwendbar sein – dh nicht zu wenig Coding enthalten

ausgewogenen Kompromis zwischen Allgemeinheit und Einfachheit darstellen

alle nötigen Daten als Parameter erhalten und nicht von globalen Variablen abhängen

Ergebnisse als Rückgabewerte zurückliefern - und Seiteneffekte möglichst vermeiden

gut dokumentiert werden

(68)

© H.Neuendorf

Rekursion Methoden-Selbstaufruf ⇒ Wiederholung ohne Schleifen !

Schleifen : Iteration ↔ 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)!

}

Interner Ablauffak(3)

3 * fak(2)

fak(2)

2 * fak(1)

fak(1)

1 * fak(0)

fak(0)

1

1

1

2

6

Basisfall :if-Zweig

Rekursionen :else-Zweige

Voraussetzungen :

1. Methode muss Basisfall enthalten

2. Rekursion muss sich auf Basisfall zubewegen

3. Basisfall muss erreicht werden

Andernfalls Stack-Overflow

Vorteil : Eleganz

Problem : Speicherbedarf

Daten aller nichtabgeschlossenen Aufrufe (incl. Rücksprungadressen) müssen auf Laufzeitstackzwischengespeichert werden !

Problem auf sich selbst zurückgeführt + vereinfacht bis zum trivialen Basisfall

fak( 2 ) aufrufen

Wert 3 zwischenspeichern

RückwegZurückgelieferte Werte mit gespeicherten Werten multiliziert

Jeder rekursive Aufruf von fak hält einen eigenen temporären Wert im Speicher

(69)

© H.Neuendorf

Rekursion Beispiele

Rekursive Modulo-Definition :public static int mod( int a, int b ) {

if( a < b ) { return a } // Basisfallelse { return ( mod( a-b, b ) ) ; } // Rekursion

}

Rekursive Exponential-Definition für ganzzahlige Exponenten :public static double power( double x, int y) {

if( y == 0 ) { return 1 } // Basisfallelse { return ( x * power( x, y-1 ) ) ; } // Rekursion

}

Rekursive Summation von ganzen Zahlen : (statt for-Schleife)public static int sum( int n ) {

if( n > 0 ) { return (n + sum( n-1 ) ) ; } // Rekursionelse { return 0 ; } // Basisfall

}

⎩⎨⎧

≥−<

= falls

falls babbabaa

ba),mod(

),mod(

1−⋅= yy xxx

niin

i

n

i+⎟⎟

⎞⎜⎜⎝

⎛= ∑∑

==

1

00

(70)

© H.Neuendorf

fibonacci(5)

fibonacci(4) fibonacci(3)

fibonacci(3) fibonacci(2) fibonacci(2) fibonacci(1)

fibonacci(2) fibonacci(1)

Rekursion ProblemeHoher 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

}

Durchführung zeigt Ineffektivität :

- Hohe Zahl von Selbstaufrufen

- Zahlreiche Zwischenergebnisse mehrfach berechnet

⇒ Simple Rekursion nicht das geeignete Mittel !

n fibonacci(n)

1 1

2 1

3 2

4 3

5 5

6 8

7 13

8 21

9 34

....................Es gibt aber auch intelligentere rekursive Lösungen …

(71)

© H.Neuendorf

Lokale + Globale Variablen - Sichtbarkeiten + Lebensdauer

Gültigkeitsbereiche : Lokale Variablen :Auf Methodenebene deklariertNur 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 deklariertGü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"

während gesamter Programmausführung

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 yy = a + x ; double d = 1.7 * PI ;

}

public static void main( String[] args ) {int y = 22 ; // lokaldouble d = 2.3 * PI ; a = 10 ;tuWas( 7 ) ;

}}

In Java gibt es keine echten globalen Variablen – es handelt sich um (statische) Attribute der Klasse

(72)

© H.Neuendorf

class Bloecke {public static double a = 1.0 ; // globalpublic static void tuWas( ) {

for( int i = 1 ; i < 10 ; i++ ) {double d = 9.0 ; // lokald = 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( ) ;

}}

Lokale Variablen :In Methoden-Blöcken deklariert bzw. in Unterblöcken von Methoden !

Nur innerhalb Block zugreifbar, in demsie deklariert wurden + in darinenthaltenen 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 for-Schleife - in der d deklariert wurde.

Auch in darin enthaltenen Unter-Blöcken angesprechbar.

Jedoch außerhalb "ihres" Blocks nichtansprechbar / verwendbar !

Blockkonzept : Zugriffsbereiche

(73)

© H.Neuendorf

Namensräume : Methoden repräsentieren eigenen Namensraum

Trotz Namensgleichheit kein Namenskonflikt :

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ängigvon 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 ;

{ int x = 3 ; } // Fehler ! OK in C++ !Regel :Wird mehrfach vergebener Variablennamebenutzt, wird immer die Variable angesprochen, in deren Namensraum man sich befindet

Namensraum 3

Namensraum 1

Namensraum 2

class Beispiel {

public static int tuWas( int para ) {int x = 10 ;x = para ;return x ;

}

public static int tuDas( int para ) {int x = 20 ;x = para ;return x ;

}

public static int x = 30 ;

}

(74)

© H.Neuendorf

Lokale + Globale Variablen - Sichtbarkeit + Lebensdauer

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

class Beispiel {

public static int x = 10 ;public static int y = 20 ;

public void m ( int par ) {int x ;x = par ;

}

// .................}

Sichtbarkeit der globalen Variablen x wird unterbrochen durch Sichtbarkeitsbereich der lokalen gleichnamigen Variablen x

Das lokale x verdeckt das gleichnamige globale x

Gutes Miko-Design : Minimized Scope →Lokale Variable sollte nur in den Blöcken sichtbar sein, in dem sie auch wirklich benötigt wirdBeim Deklarieren möglichst auch sinnvoll initialisieren⇒ Laufvariable der for-Schleife lebt nur in dieser⇒ Besser als while-Schleife mit stets externer Variablendeklaration

(75)

© H.Neuendorf

Namenskonventionen in Java-ProgrammenKeine 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()

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 .....)

CamelCase für zusammengesetzte

Namen