1.5 Programmstruktur

Werbung
1.5 Programmstruktur
Strukturierung von Programmen durch
 Unterprogramme
 Module
 Klassen
... u.a.
1.5
1
Eine Klasse „mit Gedächtnis“:
class A {
static int state = 0;
static void set(int x) { state = x; }
static
int get() { return state; }
}
1.5
2
Modul (das Modúl, die Module; module)
Klasse (class)
Bezeichnungen für Sprachkonstrukte, mit denen
verschiedenartige Elemente (members) mit gemeinsamem
Gültigkeitsbereich zusammengefasst werden können.
Im einfachsten Fall besteht ein Programm aus 1 Modul/Klasse,
im allgemeinen Fall aus beliebig vielen.
1.5
3
1.5.1 Klassen in Java
Syntax (vereinfacht):
ClassDeclaration:
[ public ] class Identifier ClassBody
ClassBody:
{ { { Modifier } Declaration } }
Declaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
.....
Initializer
FieldDeclaration:
VariableDeclaration
Initializer:
Block
Modifier:
public | static | final | . . . . .
„member“
class Math {
// math stuff
static final double PI = 3.1415926535898;
static double sin(double x) { ..... }
static double sqrt(double x) {..... }
static long seed;
static int count;
// for random
// number of calls to random
static { count = 0; }
static { seed = 71; }
// not required here
// initialization of random seed
static long random() {
count++;
long result; ................. return result;
}
}
1.5
5
Terminologie, Semantik, Konventionen:
long seed vereinbart eine Klassenvariable (= nichtlokale Variable),
die die Voreinstellung (default, 1.2.1 ) 0 hat;
die Konstante PI wird explizit initialisiert.
{ seed = 71; } sorgt für eine weitere explizite Initialisierung.
Klassennamen sollen mit einem Großbuchstaben beginnen.
Gültigkeitsbereich
aller vereinbarten Namen ist die gesamte Klasse.
Variablennamen können allerdings in einer Methode durch andere
Namen verdeckt werden (eingeschränkte Sichtbarkeit, 1.3.2)
1.5
6
Beachte:
Durch Zuweisung an eine nichtlokale Klassenvariable
kann ein Methodenaufruf ein Effekt bewirken,
der die Ausführung der Methode überdauert
und der sonst nur durch Variablenparameter
(oder Parameter mit anderen Typen, 1.6)
erzielbar wäre.
Ein solcher Effekt wird auch Nebenwirkung (side effect)
der Methode genannt.
Funktionsprozeduren, die tatsächlich eine Funktion
realisieren, sollten i.d.R. keine Nebenwirkungen haben!
1.5
7
1.5.2 Überladen von Namen
Erweiterung des Signaturbegriffs (1.4.5):
Signatur einer Klassenelements
- Name bzw.
- Name und Anzahl und Typen der Argumente (bei Methode)
Elemente einer Klasse müssen verschiedene Signaturen haben.
! Diese Regel schwächt das Kollisionsverbot von Namen ab.
Überladen (overloading) eines Namens liegt vor, wenn es mehrere
gleichnamige Elemente mit verschiedenen Signaturen gibt.
1.5
8
Beispiel - die folgende Klasse ist fast korrekt:
class
static
static
static
static
static
}
neg {
int neg = -1;
void neg(){neg = neg(neg);}
int neg(int x){return -x;}
int neg(float x){return -(int)x;}
float neg(float x){return -x;}// collides
? Welches Element ist gemeint, wenn der Name neg benutzt wird ?
Z.B. ... neg = neg(neg); ... (s.o.)
Wird durch den jeweiligen Kontext aufgelöst:
1.5
9
... neg ... ?
1.
Überladen wird statisch (!) aufgelöst:
Falls keine öffnende Klammer folgt: Variable.
[Fehler, falls keine solche Variable sichtbar.]
2. Sonst bei n Argumenten: Methode mit n Argumenten und
passenden Argumenttypen, sofern es genau eine solche gibt.
[Fehler, falls keine solche Methode sichtbar.]
3. Falls mehrere solche: die „spezifischste Methode“
(d.h. verwirf alle Methoden, zu denen es eine Methode gibt,
deren Argumenttypen verträglich mit den Argumenttypen
jener Methode sind).
[Fehler, falls diese Methode nicht eindeutig bestimmbar.]
1.5
10
Beispiel 1:
...
static void neg(){neg = neg(neg);}
...
int neg (1.)
neg(int x)
Beispiel 2:
void m(int i, char c) 
void m(short s, int i) 
m(in,ch)  
m(by,in)  
(3.)
int
short char
byte
m(ch,by)  falsch, weil weder  noch  passt (2.)
m(by,ch)  falsch, weil sowohl  als auch  passt (3.)
1.5
11
1.5.3 Bezugnahmen zwischen Klassen
class Math { ..... }
class MoreMath {
static double cos(double x) {
return Math.PI/2 - Math.sin(x); }
static double tg(double x) {
return Math.sin(x)/cos(x); }
...
}
„Punktnotation“
1.5
12
Zusammengesetzter Name (qualified identifier) (Punktnotation)
QualifiedIdentifier:
Identifier { . Identifier }
ist überall dort erlaubt, wo bisher Identifier angegeben war.
Klassendiagramm (class diagram)
ist graphische Darstellung der Klassen eines Programms
(als Rechtecke) und der Bezüge zwischen ihnen (durch Pfeile).
Standardisierte Darstellungsform:
UML (Unified Modeling Language)
1.5
13
1.5.4 Pakete
Wenn ein Programm hunderte oder tausende von Klassen umfasst,
sorgt eine weitere Strukturierung des Namensraums für bessere
Übersicht:
 Paket (package) ist eine benannte Menge von Klassen.
(Konvention: Paketname beginnt mit einem Kleinbuchstaben.)
 Programm umfasst ein oder mehrere Pakete.
 In einem Paket kann man auf die Klassen des gleichen Pakets
und - mit Einschränkungen - auf die Klassen anderer Pakete
Bezug nehmen.
1.5
14
package math; // falls nicht vorhanden, „anonymes Paket“
public class Math { ..... }
public class MoreMath {
public static double cos(double x) {
return Math.PI/2 - Math.sin(x); }
public static double tg(double x) {
return Math.sin(x)/cos(x); }
...
}
public ?
1.5
15
public sorgt dafür, dass die entsprechenden Elemente auch
außerhalb des Pakets sichtbar sind:
Vollständiger Name (fully qualified name) z.B. von tg ist
math.MoreMath.tg
Importklausel import math.MoreMath;
erlaubt Verzicht auf die Angabe des Paketnamens:
1.5
16
package myExtendedMath;
import math.MoreMath;
public class Ctg {
public static double ctg(double x) {
return 1/MoreMath.tg(x); }
}
import math.*; sorgt dafür, dass auf alle öffentlichen
Klassen aus math ohne vorangestellten Paketnamen math
Bezug genommen werden kann.
1.5
17
Syntax (vereinfacht):
CompilationUnit:
[ PackageHeader ] { Import } PackageBody
PackageHeader:
package Identifier ;
Import:
import ClassIdentifier ;
import PackageIdentifier . * ;
PackageBody:
{ ClassDeclaration }
ClassIdentifier ist ein zusammengesetzter Name, der mit einem
PackageIdentifier beginnt.
1.5
18
Ein Paket kann nicht nur Klassen, sondern auch
Unterpakete (subpackages) enthalten.
Beispiel:
Anstelle des obigen math hätten wir die folgenden drei
Pakete einführen können:
package math;
.....
// z.B. nur mit einigen Konstanten
package math.trigonometry;
.....
package math.random;
.....
Achtung:
1.5
Unterpakete werden nicht durch textuelles Schachteln
von Paketen eingeführt, sondern schlicht durch
entsprechende Namensgebung mit Punktnotation.
19
1.5.5 Bibliotheksklassen
Jedes Programmiersprachen-System umfasst von vornherein
eine große Anzahl von Klassen/Modulen, die häufig benötigte
Standard-Funktionalitäten bereitstellen - in sogenannten
Klassen-Bibliotheken (class libraries) (bzw. Modul-Bibliotheken).
Die Gesamtheit der sichtbaren Elemente einer Bibliothek
(Klassen und ihre Methoden, Variablen, ...) wird auch
Bibliotheksschnittstelle (application programming interface, API)
genannt.
1.5
20
Einige Pakete der Java-Bibliothek:
java.lang
enthält die am häufigsten benutzten Klassen,
z.B. Math mit Methoden sqrt, ...
und System mit Methoden exit, ...
- muss nicht explizit importiert werden!
java.io
enthält Klassen für die Ein/Ausgabe
java.util
enthält diverse nützliche Hilfsklassen
java.util.zip enthält Klassen für die Kompression und
Dekompression von Daten
1.5
21
1.5.6 Übersetzung und Ausführung
Übersetzer
(compiler für Hochsprache,
assembler für Maschinensprache)
macht aus dem vom Programmierer entwickelten
Quellcode
(source code)
Objektcode
(object code, binary code),
bestehend aus Maschinenbefehlen des Prozessors,
oder
Zwischencode (intermediate code, byte code),
der maschinenunabhängig ist und von einem
Interpretierer (interpreter)
ausgeführt wird.
1.5
22
Attraktiv ist
getrennte Übersetzung (separate compilation) von Programmteilen:
 Korrektur erfordert nur Neuübersetzung eines Teils
 übersetzte Teile können in Bibliotheken vorgehalten werden
Binden (linking, linkage)
fügt getrennt übersetzte Teile zu einem Programm zusammen.
Laden (loading)
kopiert Programm in den Arbeitsspeicher, wo es gestartet wird.
1.5
23
Statisches Binden (static linking):
Nachdem alle benötigten Programmteile übersetzt sind,
werden sie durch den
Binder (linker, linkage editor) zu einem Programm zusammengefügt.
Übersetzer
Binder
1.5
Bibliothek
Lader
24
Aufgaben des Binders:
 Physisches Zusammenfügen der übersetzten Teile
 entsprechendes Verschieben der relativen Adressen
 Auflösen von externen Bezugnahmen
Bindender Lader (linking loader) erlaubt dynamisches Binden
- entweder erst beim Laden
- oder sogar erst während der Ausführung (nach Bedarf!)
1.5
25
Java:  Übersetzung nach Zwischencode (byte code)
 Java Virtual Machine (JVM) praktiziert dynamisches Laden

und
interpretiert Zwischencode
Befehle:
javac MyProg.java übersetzt Quelldatei und generiert für deren
Klassen sowie für jede von diesen direkt oder
indirekt benutzte Klasse jeweils eine Datei
mit Zwischencode (.class).
java MyProg
1.5
lädt die Klasse MyProg.class und startet
deren Methode public static void main
(gegebenenfalls Nachladen weiterer Klassen).
26
Herunterladen