class Polynom{...}
)Polynom p;
)p.Grad
)p.getWert(1.1)
)Polynom p=new Polynom(3,a);
)public, private, protected
)static
)class Polynom extends Funktion{...}
)Funktion
(Datei: Funktion.java) sowie ihrer Unterklasse
Polynom
(Datei: Polynom.java) orientieren.
Diese Klassen können von irgendeiner Applikation (eine
Klasse mit Methode
main
) aufgerufen werden.
Polynom
hätte ich auch
in enger Anlehnung an den vorherigen Abschnitt eine Unterklasse
NewtonPolynom
wählen können.
main
).
Der Programmierer wird daher, allerdings nur in sehr schwacher
Weise (s. die Beispiele
Lösung eines linearen Gleichungssystems
und
Berechnung eines Newtonschen Interpolationspolynoms)
zur OOP gezwungen. Schaut man sich diese Beispiele
oder die allereinfachste Anwendung in Form des
Hello-World-Programms an, kann man keinen Nutzen von OOP
erkennen, eher nur Mystik. Das liegt u.a. daran, daß die
hier definierten Klassen in dem Sinne abstrakt sind, als
daß kein
Exemplar (auch Instanz genannt)
von ihr gebildet wird.
Listing der Klassen Funktion, Polynom
int
oder double
sind keine eigentlichen Objekte, alle Variablen von einem anderen als einem
Grunddatentyp sind stets Objekte.
Beispiel:
Mittels Polynom p;
wird ein Objekt mit Bezeichner
p
der Klasse Polynom
deklariert.
Unter Verwendung des
new
-Operators
und einem Konstruktor
gleichen Namens wie die Klasse wird das Objekt sodann
allokiert, d.h.
ihm Speicherplatz (dynamisch) reserviert:
Durch
double[] aa={1,2,3,4}; p=new Polynom(3,aa)
wird das Polynom
p(x)=1+2x+3x^2+4x^3 (mit dem Koeffizientenvektor aa
)
initialisiert.
Auf die Daten (Mitgliedsvariable) und Methoden eines Objekts wird mit der Punkt-Notation zugegriffen.
Listing der Klassen Funktion, Polynom
static
kenntlich gemacht werden.
Beispiel:
Ein Objekt namens p
der Klasse Polynom
hat als Mitgliedsvariable
int Grad
und den Koeffizientenvektor double[] a
.
Mittels
p.Grad, p.a
könnte von außen auf die
Daten von p
zugegriffen werden, wenn diese nicht
als
private
deklariert worden wären (s.u. unter
Zugriffsrechte).
Listing der Klassen Funktion, Polynom
void
festgelegt
wird). Methoden können in runden Klammern eingeschlossene
Parameter (Argumente), auch in Form von
Parameterlisten, enthalten. Die runden Klammern müssen
immer dem Bezeichner einer Methode angefügt werden - auch wenn es keinen
Parameter gibt.
Polynom
(und auch
ihr Objekt p
) u.a. über
von denen HornerKoeffizienten() als Wert einen Vektor (private double[] HornerKoeffizienten(double x) public double getWert(double x) public double getAbleitung(double x)
double[]
)
zurückgibt, während die anderen Methoden
als Wert double
haben. Ferner haben sie alle eine vorgegebene Zahl x
als Parameter. Zu den
Zugriffsrechten später.
double y=p.getWet(3);
kann die Methode
getWert
durchgeführt, hier der Wert des Polynoms an der
Stelle 3 berechnet werden.
Man sagt auch, daß eine
Klasse, in der p
deklariert wird, sich der (öffentlichen!)
Methode getWert()
des Objektes p
bedient.
Die Werte von Methoden werden mit Hilfe desclass Polynom extends Funktion{ ... ... private double[] HornerKoeffizienten(double x){ double[] b = new double[this.Grad]; b[Grad-1]=a[Grad]; for(int j=Grad-2;j>=0;j--) b[j]=a[j+1]+x*b[j+1]; return b; }//ende HornerKoeffizienten public double getWert(double x){ if (Grad==0) return a[0]; else{ double[] b=HornerKoeffizienten(x); return b[0]*x+a[0]; }//else }//Ende getWert public double getAbleitung(double x){ Polynom q=this.Horner(x); return q.getWert(x); }//Ende getAbleitung ... ... }//Ende class Polynom
return
Operators übergeben.
Die Methode getAbleitung
benutzt eine weitere Methode
Horner
der Klasse Polynom
, die
insofern etwas aus der Rolle fällt, weil sie
als Wert ein Objekt just derselben Klasse
Polynom
hat! Es ist das Polynom,
das durch die Koeffizienten b[i]
des Horner-Schemas
gebildet wird:
Theoretisch ist eine Anweisungclass Polynom extends Funktion{ ... ... public Polynom Horner(double xi){ double[] b=HornerKoeffizienten(xi); Polynom p=new Polynom(this.Grad-1,b); //rekursiv! return p; //p_n(x)=p_{n-1}(x)*(x-xi)+p_n(xi), p=p_{n-1} }//ende Horner ... ... }//Ende class Polynom
p.Horner(1).Horner(2).getWert(3);
möglich.
this
verwendet. Er zeigt
auf das aktuelle Objekt.
Horner
wird ein
Konstruktor verwendet.
Listing der Klassen Funktion, Polynom
new
.
Konstruktoren sind ganz spezielle Methoden, sie haben
denselben Namen wie die Klasse.
Eine Klasse muß nicht zwingend
einen Konstruktor vorsehen. Dann kann man immer noch mit einem
voreingestellten "minimalen" Default-Konstruktor ein Objekt allokieren.
Der Konstruktor liefert keine Werte, dennoch steht er ohne den Zusatz
void.
Polynom
ist folgendermaßen vereinbart:
Das Polynom wird "konstruiert", wenn sein Grad und der Koeffizientenvektor übergeben werden. Hier ist die Verwendung des Zeigersclass Polynom extends Funktion{ ... ... //Konstruktor: public Polynom(int Grad, double[] a){ this.Grad=Grad; this.a=a; } ... ... }//Ende class Polynom
this
nur dann nicht notwendig, wenn man als Parameter-Bezeichner des
Konstruktors nicht dieselben wie die für die Mitgliedsvariablen
verwendet hätte, z.B.
Die Verwendung von//Konstruktor: public Polynom(int n, double[] b){ Grad=n; a=b; }
this
hat den Vorteil, daß man sich
in das Gedächtnis zurückruft, daß Grad, a
Mitgliedsvariable eines Polynom
-Objektes sind.
Listing der Klassen Funktion, Polynom
public Polynom(int Grad, double[] a)
hätte durch
überladen werden können, indem der erste Konstruktor mit Hilfe des Zeigerspublic Polynom(double[] a){ this(a.length-1,a);//length ist ein Attribut eines Feldes }
this
aufgerufen wird (Konstruktoren können sich gegenseitig mit Hilfe
von this
aufrufen). Danach können beide
Konstruktoren Verwendung finden.
Listing der Klassen Funktion, Polynom
public
(öffentliches Zugriffsrecht, Sichtbarkeit)
oder private
lautet.
Ersteres erlaubt jeder Klasse,
bzw. jedem Objekt
auf sie zuzugreifen (und die öffentlichen Daten zu verändern),
letzteres gewährt dieses Recht nur innerhalb der eigenen Klasse.
Für Methoden wird hierdurch die Dienstbarkeit für andere Klassen
festgelegt, in der Regel bieten Objekte ihre Dienste anderen Objekten
an.
protected
erlaubt das Zugreifen auch für
Ober- und Unterklassen (s.u.), also für das gesamte
Paket (package
).
public
.
private int Grad;
Hätten wir die Variable Grad
der Klasse
Polynom
nicht als private
deklariert, könnte eine andere Klasse
z.B. durch p.Grad=123;
einen "falschen" Grad erzeugen.
Will man jedoch Unterklassen (s.u.) definieren, k"onnen diese
private
Attribute und Methoden nicht erben. Diese müssen wenigstens
protected sein.
Grundsätzlich sind private Daten und Methoden für andere Klassen
nicht sichtbar. Die Methode HornerKoeffizienten
ist
private
, da sie außerhalb dieser Klasse nicht
benutzt werden soll.
Listing der Klassen Funktion, Polynom
Math
. Hier sind naturgemäß
alle Variablen und Methoden statisch (static
). Man ruft
sie über den Bezeichner der Klasse auf, z.B.
Math.sin
.
Polynom p;
ergibt eine (Referenz-) Variable mit
Bezeichner p
vom Typ Polynom
.
Erst durch Initialisierung in Verbindung mit new
wird ein konkretes
Objekt erzeugt. Man sagt, es wird eine Instanz der Klasse als Vorlage
gebildet: Durch
wird im Heap Platz gemacht für die Daten vonp=new Polynom(3,aa);
p
, man sagt p ist initialisiert oder
allokiert.
p
ist wie jede Objektvariable einschließlich Arrays und Strings
eine Referenzvariable im Gegensatz zu
int i; char b; double x;
, den Grunddatentypen.
Dieser Unterschied kommt bei der Anweisung q=p;
für zwei
Objekte p, q zum Tragen: hierdurch werden die Referenzen
gleich, d.h. in Folge weisen beide auf denselben Heap, es wird keine
Kopie angelegt!
Ebenfalls sehr wichtig ist dies, wenn man Referenzvariable
als Parameter von Methoden übergibt ("Call by Reference").
Polynom
ist eine Unterklasse der (abstrakten)
Klasse Funktion
.
Dieses erkennt man an der ersten Zeile
in Polynom.java
:
Mit dem Zusatzclass Polynom extends Funktion{ ... ... }
extends Funktion
definiert sich die Klasse
Polynom
als Unterklasse der Klasse
Funktion
.
Der Vorteil dieses Konzepts wird durch Vererbung
und Polymorphie charakterisiert.
Funktion
denkbar. Eine lautet so:
public class HutFunktion extends Funktion{ public double getWert(double x){ double y=0; if ((x>-1) & (x<=0)) y=x+1; if ((x>0) & (x<=1)) y=1-x; return y; } }
Listing der Klassen Funktion, Polynom
Funktion
genauer an: es sind die drei Methoden
getWert, getAbleitung,
getWertetabelle
. Die ersten beiden Methoden wurden von
der Unterklasse Polynom
überlagert, sie
wurden "optimal" auf eine Polynomfunktion zugeschnitten. Die
abstrakte Klasse Funktion
erwartet von jeder ihrer
Unterklasse eine Überlagerung
(oder Redefinierung) zumindestens der Methode getWert
.
Wird getAbleitung
nicht überlagert, so wird der
"Notnagel" der Klasse Funktion
(numerische Differentiation)
benutzt. Anders ist es mit der Methode getWertetabelle
von Funktion
: auf diese kann und sollte von jedem Objekt
jeder Unterklasse zugegriffen werden:
Wichtig ist, daß hier als Methodeclass Funktion{ ... ... public double[][] getWertetabelle(double a, double b, int Aufloesung){ double dx=(b-a)/Aufloesung; double[] x=new double[Aufloesung+1]; double[] y=new double[Aufloesung+1]; double[][] z=new double[2][Aufloesung+1]; for(int i=0;i<=Aufloesung;i++){ x[i]=a+i*dx; y[i]=getWert(x[i]);} z[0]=x; z[1]=y; return z; } ... ... }//Ende class Funktion
getWert
nicht etwa
die "Stellvertreter-Methode" in Funktion
verwendet
wird, sondern die jeweils überlagerte Methode der Unterklasse.
Funktion
eingeführt werden, auf die jedes Objekt einer Unterklasse
zugreifen kann.
super
. Es ist denkbar, daß
der Konstruktor einer Unterklasse zusätzliche Parameter besitzt.
Listing der Klassen Funktion, Polynom
Funktion
enthält, könnte dort
unbedenklich (jedenfalls syntaktisch) ein Objekt der
Unterklasse Polynom
eingesetzt werden.
Als Beispiel sei die Klassenmethode
Tools.Zeichne
genannt, die den Grafen einer Funktion zeichnet. Weitere Methoden
wie Numerische Integration oder Nullstellenbestimmung sind
denkbar.
public abstract class Funktion{ public String Name; public abstract double getWert(double x); //muss in jeder Unterklasse //ueberlagert werden public double getAbleitung(double x){ return (getWert(x+0.001)-getWert(x-0.001))/0.002; }//Ende getAbleitung public double[][] getWertetabelle(double a, double b, int Aufloesung){ double dx=(b-a)/Aufloesung; double[] x=new double[Aufloesung+1]; double[] y=new double[Aufloesung+1]; double[][] z=new double[2][Aufloesung+1]; for(int i=0;i<=Aufloesung;i++) {x[i]=a+i*dx; y[i]=getWert(x[i]);} z[0]=x; z[1]=y; return z; }//Ende getWertetabelle }//Ende class Funktion class Polynom extends Funktion{ //Attribute, Datenelemente, Mitgliedsvariable: private int Grad; private double a[]; //Koeffizienten (p=a0+a1*x+....+an*x^n) //Konstruktor: public Polynom(int Grad, double[] a){ this.Grad=Grad; this.a=a; }//Ende 1. Konstruktor public Polynom(double[] a){ this(a.length-1,a); }//Ende 2. Konstruktor //Methoden: private double[] HornerKoeffizienten(double xi){ double[] b = new double[this.Grad]; b[Grad-1]=a[Grad]; for(int j=Grad-2;j>=0;j--) b[j]=a[j+1]+xi*b[j+1]; return b; }//ende HornerKoeffizienten //Eine Methode, die wieder ein Polynom erzeugt: public Polynom Horner(double xi){ double[] b=HornerKoeffizienten(xi); Polynom p=new Polynom(this.Grad-1,b); //Bemerkenswert: Rekursiv return p; //p_n(x)=p_{n-1}(x)*(x-xi)+p_n(xi), p=p_{n-1} }//ende Horner public double getWert(double x){ if (Grad==0) return a[0]; else{ double[] b=HornerKoeffizienten(x); return b[0]*x+a[0]; }//Ende else }//Ende getWert public double getAbleitung(double x){ Polynom q=this.Horner(x); return q.getWert(x); }//Ende getAbleitung }//ende class Polynom
Funktion, Polynom, HutFunktion
nutzt:
Die letzten Zeilen verdienen eine Bemerkung: Hier werden von dem Polynom p alle Ableitungen an der Stellepublic class Test1{ public static void main(String[] args){ //Wertetabelle der Hautfunktion: double[][] z=new double[2][10]; double a=-2; double b=2; int Aufloesung=10; HutFunktion f=new HutFunktion(); z=f.getWertetabelle(a,b, Aufloesung); for(int i=0;i<=10;i++) System.out.println(z[0][i]+" "+z[1][i]); //Berechnung von Funktionswert und Ableitung eines Polynoms an einer Stelle xi: double[] aa={1,2,3,4}; Polynom p=new Polynom(3, aa); //oder ...Polynom(aa); Polynom q=new Polynom(aa); double xi=1; int j=1; for(int i=0;i<=3;i++){//die ersten drei Ableitungen an der Stelle xi System.out.println("p^"+i+"("+xi+")="+j*q.getWert(xi)); if (i<3) q=q.Horner(xi); j*=(i+1); //(i+1)! }//Ende for }//Ende main }//Ende Test1
xi
berechnet. Dies geschieht durch mehrmaliges Anwenden des
Horner Schemas, genauer der Methode Horner
,
die ja gerade das Polynom liefert, das von den Koeffizienten
des Horner Schemas bestimmt wird. Der Befehl
q=q.Horner(xi)
ist also rekursiv.
Funktion
).
java.lang
,
andere wie java.applet
oder java.awt
(siehe Applets)
müssen importiert werden.
OOP mit der Klasse Matrix und der Unterklasse TridiagonalMatrix