Unterprogramme, Methoden
Klassen und Objekte
Parameterbergabe von Referenzen
Kapselung und Zugriffskontrolle
Konstruktoren
Datentyp Complex
Unterprogramme sind Prozeduren und Funktionen, in Java werden sie als Methoden bezeichnet.
Unterprogramme bestehen aus einem Kopf (head) und einem Rumpf (body)
der Rumpf ist eine Zusammenfassung von Anweisungen
in dem Kopf wird der Name des Unterprogramms definiert, sowie die Parameter und der Ergebnistyp
bei Prozeduren ist der Ergebnistyp void
die Parameter (als formale Parameter bezeichnet) definieren in dem Rumpf lokale Variablen
Aufruf einer Prozedur durch angabe des Namens, gefolgt von den
aktuellen Parametern (getrennt durch Komma) in Klammern
name( p1, p2, f(p3), p4+5 )
Signatur, Aufrufschnittstelle: Anzahl und Typen der Parameter sowie des Ergebnistyps
berladen: Prozeduren mit gleichem Namen, die sich in der Signatur unterschieden (in Java nur der formalen Parameter), bei der Auswahl muss die Eindeutigkeit gewhrleistet werden
Parameterbergabe:
Wertaufruf (call by value):
der berechnete Wert der Ausdrucks wird verwendet
(in Java fr elementare Typen)
Referenzaufruf (call by reference):
nur bei Variablen als Parameter, Ermglicht Zuweisungen
an die Variable im Rumpf
(in Java fr Objekte)
Namensaufruf (call by name):
textuelle Substitution wie bei LISP/Scheme
(nicht in Java)
die Prozedur public static void main(String[] args) { }
wird vom Java-Interpreter als erste ausgefhrt
bei rekursiven Prozeduren wird im Rumpf die Prozedur selbst wieder aufgerufen,
void prozedur( parameter ) block; typ funktion( parameter ) { ... return (typ) wert; ... } typ methode( typ_1 name_1, ..., typ_n name_n ) { ... int x = (int)name_1; int y = funktion( name_2, 4711 ); int z = name_3 + name_n; ... } public static void main(String[] args) { // die Hauptprozedur, // d.h. die erste die ausgefhrt wird }
Beispiele:
public class Unterprogramme { void prozedur() { } int funktion() { return 4711; } int quadrat(int a) { return a*a; } double quadrat(double a) { return a*a; } int name(int a) { int b = quadrat( 2 ); return b+a; } long fakultaet(long n) { if ( n <= 1l ) { return 1l; } else { return n * fakultaet( n-1l); } } double summe(double[] a) { double sum = 0.0; for ( int i = 0; i < a.length; i++ ) { sum += a[i]; } return sum; } void main() { prozedur(); int n = funktion(); int i = quadrat(n); int j = name( 3 ); long k = fakultaet( 10 ); double[] z = { 1.0, 1.2, 3.2, 4.6, 9.2 }; double s = summe( z ); System.out.println("n = " + n); System.out.println("i = " + i); System.out.println("j = " + j); System.out.println("k = " + k); System.out.println("s = " + s); } public static void main(String[] args) { // die Hauptprozedur, (new Unterprogramme()).main(); } }
public class Ueberladen { void problem(int a, long b) { } void problem(long a, long b) { } void problem(long a, int b) { } void ratemal() { problem( 1, 2L ); // ok problem( 1L, 2 ); // ok problem( 1, 2 ); // fehler } long problem(long a, long b) { // fehler return a*b; } }
public class Uebergabe { class Unter { int a = 0; int b = 1; } void wert( int c ) { c = c + 55; } void referenz( Unter u ) { int x = u.a * 3; u.b = x + 14; } void unveraendert( Unter u ) { u = new Unter(); int x = u.a * 3; u.b = x + 14; } void ratemal() { int w = 3; wert( w ); // w == 3 Unter u = new Unter(); referenz( u ); // u.a == 0 // u.b == 14 unveraendert( u ); // u.a == 0 // u.b == 1 } }
public class Rekursion { long fakultaet(int n) { if ( n <= 1 ) { return 1l; } else { return n * fakultaet( n-1); } } double summe(double[] a) { double sum = 0.0; for ( int i = 0; i < a.length; i++ ) { sum += a[i]; } return sum; } double reksumme(double[] a) { return reksumme(a,a.length); } double reksumme(double[] a, int n) { if ( n == 0 ) return 0.0; return reksumme(a,n-1) + a[n-1]; } long potenz(int b, int e) { // berechne b hoch e // if ( e < 0 ) { b = 1/b; e = -e; } if ( e == 0 ) return 1l; if ( e == 1 ) return (long)b; return b * potenz( b, e-1 ); } long quadrat(long b) { // berechne b*b return b*b; } long potenzFast(int b, int e) { // berechne b hoch e // if ( e < 0 ) { b = 1/b; e = -e; } if ( e == 0 ) return 1l; if ( e == 1 ) return (long)b; if ( e % 2 == 0 ) return quadrat( potenzFast( b, e/2 ) ); return b * potenzFast( b, e-1 ); } void main() { long k = fakultaet( 10 ); double[] z = { 1.0, 1.2, 3.2, 4.6, 9.2 }; double s = summe( z ); double r = reksumme( z ); long p = potenz( 10, 15 ); long f = potenzFast( 10, 15 ); System.out.println("k = " + k); System.out.println("s = " + s); System.out.println("r = " + r); System.out.println("p = " + p); System.out.println("f = " + f); } public static void main(String[] args) { // die Hauptprozedur, (new Rekursion()).main(); } }
public class Summe { static double[] betrag = null; static double summe() { double s = 0.0; for (int i = 0; i < betrag.length; i++ ) { s += betrag[i]; } return s; } public static void main(String[] args) { betrag = new double[args.length]; for (int i = 0; i < args.length; i++) { betrag[i] = 0.0; try { betrag[i] = Double.parseDouble( args[i] ); // betrag[i] = Double.valueOf( args[i] ).doubleValue(); } catch (NumberFormatException e) { } } System.out.println("Eingegeben wurden " + args.length + " Zahlen"); double s = summe(); System.out.println("Die Summe ist " + s); } }
Klassen bieten die Zusammenfassung von Funktionen, Prozeduren und Variablen zu einem bestimmten Zweck. (Abstraktion von einzelnen Methoden zu Modulen oder Gruppen.)
Klassen sind zusammengesetzte Datentypen.
die Klassendeklaration definiert die Bestandteile:
Ein Objekt ist ein Exemplar einer Klasse (auch als Instanz bezeichnet)
Ein Objekt einer Klasse kann durch das Schlüsselwort new erzeugt werden.
ein Objekt enthlt die Bestandteile:
Der Zugriff auf Objektbestandteile erfolgt mit dem Punktoperator
'.
'
Variablen einer Klasse deklariert man durch den Namen der Klasse, gefolgt vom Namen der Variablen Klasse var (entspricht Klasse var = null). Der Variablen muss anschliessend ein (neues) Objekt zugewiesen werden.
Konstruktoren sind spezielle Methoden mit dem Namen der Klasse ohne Rckgabeparameter. Bei der Erzeugung eines neuen Objekts wird entsprechend der aktuellen Parameter ein passender Konstruktor ausgewhlt, der die Instanz-Variablen initialisieren kann.
public class Klassen { static int klassen = 0; int meineNummer = 0; Klassen() { meineNummer = klassen++; } static String statistik() { return "Erzeugte Objekte = " + klassen; } public String toString() { return "Meine Nummer = " + meineNummer + " von " + klassen; } public static void main(String[] args) { System.out.println( Klassen.statistik() ); Klassen einz = new Klassen(); Klassen zwei = new Klassen(); Klassen drei = new Klassen(); Klassen vier = new Klassen(); Klassen fuenf = new Klassen(); System.out.println( statistik() ); System.out.println("einz: " + einz.toString()); System.out.println("zwei: " + zwei); System.out.println("vier: " + vier); System.out.println("drei: " + drei); System.out.println("fuenf: " + fuenf); } }
Java-Programme werden mittels Klassen definiert. Jede öffentliche (d.h. als public deklarierte) Klasse muß in einer separaten Datei gespeichert werden. Der Name der Datei muß mit dem Namen der public-Klasse übereinstimmen (z.B. muß die Klasse public class Test in der Datei Test.java gespeichert werden).
Der Speicherbereich für das Objekt wird automatisch allokiert. Wenn das Objekt nicht mehr gebraucht wird (d.h. keine Variable referenziert mehr das Objekt), wird der Speicherbereich während eines Garbage-Collection-Vorganges wieder freigegeben (Speicherrecycling). Das heißt, daß im Gegensatz zu C/C++ kein expliziter `delete'-Operator benötigt wird.
In Java knnen Prozeduren nur innerhalb von Klassen definiert werden. Prozeduren knnen zu einer Klasse oder zu Objekten der Kasse gehren. Es gibt in Java keine globalen Variablen oder Methoden.
public class Card { int number; static int base = 5; public static String version = "1.0"; public Card(int n) { number = n; } public int getNumber() { return number; } public static int getBase() { return base; } public int getDiff() { return number - base; } public static void main(String[] args) { Card c = new Card(7); System.out.println(c.version+":"+ c.getNumber()+"-"+c.getDiff()+"="+ Card.getBase()); } }
Die Ausgabe dieses Programms ist 1.0:7-2=5.
Wertaufruf (call by value): der berechnete Wert der Ausdrucks wird verwendet (in Java fr elementare Typen)
Referenzaufruf (call by reference): nur bei Variablen als Parameter, Ermglicht Zuweisungen an die Variable im Rumpf (in Java fr Objekte)
Die bergabe von Objektrefrenzen ermglicht die Vernderung von bergebenen Objekten in der aufrufenden Methode.
public class Confuse { static class Reference { int val; } public int confuse( int a, int b ) { a = 1; a = b + a; return a; } public Integer confuse( Integer a, Integer b ) { a = new Integer(1); a = new Integer( b.intValue() + a.intValue() ); return a; } public Reference confuse( Reference a, Reference b ) { a.val = 1; a.val = b.val + a.val; return a; } public static void main(String[] args) { Confuse c = new Confuse(); int m = 4; int n = c.confuse( m, m ); System.out.println("m = " + m); System.out.println("n = " + n); Integer i = new Integer(4); Integer j = c.confuse( i, i ); System.out.println("i = " + i); System.out.println("j = " + j); Reference k = new Reference(); k.val = 4; Reference l = c.confuse( k, k ); System.out.println("k = " + k.val ); System.out.println("l = " + l.val ); } }
Das Problem kann durch Zugriffskontrolle gelst werden.
Klassen bzw. Objekte knnen ihre Variablen und Methoden in verschiedenen Abstufungen kapseln (einschliessen). Dabei werden nur die Variablen oder Methoden nach aussen, d.h. fr andere Objekte sichtbar gemacht, die notwendig sind. Man spricht auch vom Geheimnisprinzip. Die ffentlich zugnglichen Variablen und Methoden werden meist noch durch Interfaces (s.u.) definiert. Vorteil: die Interna knnen beliebig modifiziert werden solange die Schnittstelle und deren Semantik erhalten bleibt.
Java unterschiedet public
, private
,
protected
und default Zugriffsrechte.
public
: vllig ffentlich
private
: nur in Objekten der eigenen Klasse sichtbar
protected
: in Objekten der Klassehierarchie sichtbar
default: im gleichen Package sichtbar
Beispiele siehe Abschnitt "Sichtbarkeit".
Der Kontrakt zwischen dem/der Entwicklerin einer Klasse und einem Anwender besteht aus der Syntax und Semantik der Aufrufschnittstelle.
Konstruktoren dienen der Initialisierung der Objekt-Variablen. Klassen-Variablen werden ein einziges mal vor der ersten Verwendung der Klasse initialisiert.
der Name der Konstruktoren muss der Name der Klasse sein
Konstruktoren sehen aus wie Methoden ohne Rckgabetyp Definition
Konstruktoren knnen wie Methoden berladen werden
fr Konstruktoren gelten die blichen Zugriffsspezifikationen
Konstruktoren der Superklasse knnen explizit mit
super(...)
verwendet werden
andere Konstruktoren der eigenen Klasse knnen explizit mit
this(...)
verwendet werden
Wir entwickeln eine Klasse Complex
, die
fr die Arithmetik komplexer Zahlen verwendet werden kann.
Der Konstruktor soll aus einem Paar reeler Zahlen (a,b)
eine komplexe Zahl a + i b
machen.
Methoden und Konstanten:
Null ist 0 + i 0
, Einz ist 1 + i 0
,
Feststellen des Real- und Imaginr-Teils,
Anzeige mit toString()
von Object
,
Test auf Gleichheit,
Addition: (a + i b) + (c + i d)
= (a+c) + i (b+d)
,
Subtraktion analog, negative Zahl,
Multiplikation: (a + i b) * (c + i d)
= (ac-bd) + i (ad+bc)
,
Konjugation: con(a + i b)
= a - i b
,
Betrag: abs(a + i b)
= a a + b b
,
Inverses: inv(a + i b)
= con(a + i b)/abs(a + i b),
Division: (a + i b) / (c + i d)
= (a + i b) * inv(c + i d),
/** * Klasse zum Rechnen mit Komplexen Zahlen * hk, 9.12.2001 * **/ public class Complex { /* Die Datenstruktur */ private double re; // der Realteil private double im; // der Imaginrteil /* Die Konstruktoren erzeugen aus einem Paar von double Zahlen eine Komplexe Zahl */ public Complex(double r, double i) { re = r; im = i; } public Complex(double r) { this(r,0.0); } public Complex() { this(0.0); } /* Konstanten: 1, 0 und i */ public static final Complex ZERO = new Complex(); public static final Complex ONE = new Complex(1.0); public static final Complex I = new Complex(0.0,1.0); /* Bestimmen des Real- und Imaginr-Teils */ public double reTeil() { return re; } public double imTeil() { return im; } /* Darstellung als Zeichenkette */ public String toString() { String s = "" + re; if ( im < 0 ) s += " - " + (-im) + "i"; else s += " + " + im + "i"; return s; } /* Vergleich zweier Komplexer Zahlen */ public boolean equals(Complex b) { return ( re == b.reTeil() && im == b.imTeil() ); } /* Arithmetische Operationen: +, -, - */ public Complex add(Complex b) { return new Complex(re + b.reTeil(), im + b.imTeil()); } public Complex subtract(Complex b) { return new Complex(re - b.reTeil(), im - b.imTeil()); } public Complex negate() { return new Complex(-re,-im); } /* Arithmetische Operationen: Konjugierte, Absolut Betrag */ public Complex conjugate() { return new Complex(re,-im); } public double abs() { return ( re * re + im * im ); } /* Arithmetische Operationen: *, Inverse, / */ public Complex multiply(Complex b) { return new Complex(re * b.reTeil() - im * b.imTeil(), re * b.imTeil() + im * b.reTeil() ); } public Complex inverse() { double a = this.abs(); return new Complex(re/a, -im/a); // Konjugierte } public Complex divide (Complex b) { return this.multiply( b.inverse() ); } }
Anwendungsbeispiel
/** * Testen der Klasse zum Rechnen mit Komplexen Zahlen * hk, 9.12.2001 * **/ public class ComplexTest { public static void main(String[] args) { Complex a = new Complex(2.0,3.0); System.out.println("a(2,3) = " + a); System.out.println("Null(0,0) = " + Complex.ZERO); System.out.println("Eins(1,0) = " + Complex.ONE); Complex b = Complex.ONE; b = b.add(a); System.out.println("b(3,3) = " + b); Complex c = new Complex(3.0,3.0); System.out.println("c(3,3) = " + c); boolean t = c.equals(b); System.out.println("t(true) = " + t); Complex d = c.conjugate(); System.out.println("d(3,-3) = " + d); double e = c.abs(); System.out.println("e(18) = " + e); Complex f = c.multiply(d); System.out.println("f(18,0) = " + f); // c*conjugate(c) = abs(c) t = e == f.reTeil(); System.out.println("t(true) = " + t); // i*i = -1 Complex g = Complex.I.multiply(Complex.I); System.out.println("g(-1,0) = " + g); // 1/i = -i Complex h = Complex.ONE.divide(Complex.I); System.out.println("h(0,-i) = " + h); } }
© Universität Mannheim, Rechenzentrum, 1998-2003.
Heinz Kredel Last modified: Mon Dec 9 21:46:51 CET 2002