8. Programmieren mit Objekten - auf Matthias-Draeger.info
8. Programmieren mit Objekten - auf Matthias-Draeger.info
8. Programmieren mit Objekten - auf Matthias-Draeger.info
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>8.</strong> <strong>Programmieren</strong> <strong>mit</strong> <strong>Objekten</strong><br />
<strong>8.</strong>1 Objektgeflechte,<br />
<strong>8.</strong>2 Lineare Listen<br />
<strong>8.</strong>3 Spezielle Objekte: Felder<br />
<strong>8.</strong>4 Spezielle Objekte: Zeichenketten
Objektoriente Programmierung<br />
(object oriented progeramming)<br />
besitzt drei Merkmale:<br />
1. Klassenbasierung: Klassentyp fasst Attribute (Felder)<br />
und <strong>auf</strong> den Werten des Typs vorgesehene Operationen<br />
zusammen. Das Sprachkonstrukt heißt Klasse.<br />
2. Datenabstraktion: Operationsschnittstelle (interface)<br />
macht von Implementierung der Methoden und<br />
Repräsentation der Daten als Attribute unabhängig.<br />
Später!<br />
3. Vererbung ("Gemeinsamkeiten von Klassen / <strong>Objekten</strong><br />
ausnutzen")<br />
Später!<br />
hs / fub - alp2-08 2
Beispiel: Bankkunden und ihre Konten<br />
checking<br />
saving<br />
2<br />
owner<br />
owner<br />
public class Account {<br />
public int accNo;<br />
private Customer owner;<br />
private int balance;<br />
public double getBalance() {<br />
return (double) balance;<br />
}...<br />
public void withdraw(…){…}<br />
public void deposit(double amount){<br />
..}<br />
public Account(int accNo,<br />
Customer c){<br />
}<br />
public class Customer {<br />
int custNo;<br />
name long; // encrypted<br />
Account checking, saving;<br />
...}<br />
hs / fub - alp2-08 3
Verkettete Datenstruktur (Geflecht) der Objekte<br />
Customer<br />
Account<br />
c1 = new Customer(...);<br />
c2 = new Customer(...);<br />
c3 = new Customer(...)<br />
c1.checking = new Account(4711,this);<br />
c2.checking = c1.checking;<br />
c2.saving = new Account(553,this);<br />
c3.checking = new Account(6536,this);<br />
c3.saving = new Account(777,this);<br />
public Account(int acc, Customer c){<br />
accNo=acc;<br />
owner = c;<br />
balance = 0;<br />
}<br />
hs / fub - alp2-08 4
Andere mögliche Initialisierungen …<br />
Account acc1= new Account (4711, new Customer(…));<br />
acc11.owner.checking = acc11;<br />
anonym, zeigt<br />
aber in jedem<br />
Fall ein Objekt.<br />
… im Gegensatz zu public Account(int acc, Customer c)<br />
Objektverweis<br />
was kann schief gehen?<br />
hs / fub - alp2-08 5
Rekursiver Datentyp:<br />
Objekt vom Typ K verweist <strong>auf</strong> Objekt vom Typ K (?)<br />
Beispiel: Polygonzug<br />
public class Poly {<br />
private static int<br />
count=0;<br />
Point p;<br />
Poly next;<br />
polyStart =<br />
new Poly(new Point(3,4),<br />
new Poly(new Point(5,10),<br />
new Poly(new Point(10,10),<br />
new Poly (new Point(10,13)null))));<br />
public Poly(Point p,<br />
Poly next);<br />
...<br />
}<br />
Liste wird "von hinten" hinten nach<br />
vorne konstruiert".<br />
hs / fub - alp2-08 6
Vergleich <strong>mit</strong> Listen in funktionalen Sprachen<br />
• Liste als Sprachelement:<br />
Haskell: [5,3,7]<br />
abkürzende Schreibweise für (5:(3:(4:[])))<br />
Konstruktor<br />
"null" (leere Liste)<br />
Elemente vorne an die Liste anfügen:<br />
cons:: a -> [a] -> [a]<br />
cons x liste = (x:liste)<br />
cons identisch <strong>mit</strong> dem<br />
infix-Operator (:)<br />
LISP: cons<br />
• Generische Listen: Basistyp als Parameter ("a")<br />
hs / fub - alp2-08 7
Lineare Liste<br />
public class IList {<br />
final Type head;<br />
final IList tail;<br />
null<br />
Leere Liste<br />
IList (Type x,IList rest){<br />
head = x;<br />
tail = rest;<br />
}<br />
// pre: nichtleere Liste<br />
boolean find(int x){<br />
if (head==x) {return true;}<br />
else {if (tail==null) {return false;}<br />
else {return tail.find(x);}<br />
}<br />
}<br />
... }<br />
"Eine Liste ist leer oder besitzt ein<br />
erstes Element und eine Restliste"<br />
einelementige<br />
Liste<br />
tail: null<br />
head: 3<br />
hs / fub - alp2-08 8
cons lineare Listen<br />
class IList{...<br />
// pre: Liste nicht leer<br />
public IList cons (Type elem){<br />
return (new IList(elem, this));<br />
}...<br />
}<br />
tail:<br />
head: 5<br />
tail:<br />
head: 3<br />
5:(3:(4:[]))<br />
tail: null<br />
head: 4<br />
hs / fub - alp2-08 9
Veränderbare lineare Listen, einfach verkettet <strong>mit</strong> Wächter<br />
null<br />
public class LList {<br />
Node first, last;<br />
null<br />
Liste existiert<br />
nicht (!)<br />
public LList(){<br />
first = new Node();<br />
last = first;<br />
}...<br />
public void insert(Object x){<br />
//vorne Einfügen<br />
first=new Node(x,first);<br />
val: -<br />
next: -<br />
first<br />
} val: o val: -<br />
next next: -<br />
public class Node {<br />
Object val;<br />
Node next;<br />
first last<br />
}<br />
last<br />
leere<br />
Liste<br />
hs / fub - alp2-08 10
Vorteile eines Wächterelements<br />
boolean find (Object o){<br />
last.val = o;<br />
Node ptr=first;<br />
do {<br />
if (ptr.val.equals(o)){<br />
return ptr!=last;}<br />
ptr = ptr.next;<br />
} while (ptr !=last);<br />
// never beyond this point..<br />
return ptr != last;<br />
}<br />
val: x<br />
next<br />
first<br />
val: y<br />
next<br />
Suche negativ ("nicht gefunden") : ptr==last<br />
val: o<br />
next: -<br />
last<br />
Vorteil: keine Sonderfälle zu beachten.<br />
hs / fub - alp2-08 11
Variante: zirkuläre einfach verkettete Liste<br />
last entbehrlich. Ende erreicht, wenn node.next == first<br />
public class CLList {<br />
Node first;<br />
public CLList () {<br />
first.next = last;<br />
}<br />
...<br />
}<br />
Wächterelement am Anfang(?) der<br />
Liste.<br />
Noch mal Konstruktor:<br />
public CLList (Object x) {<br />
this.insert(o);<br />
}<br />
hs / fub - alp2-08 12
Einfügen in lineare zirkuläre Liste <strong>mit</strong> Wächter<br />
Mit dem Knoten-Konstruktor:<br />
public Node(Object x,Node n){<br />
val=x;<br />
next=n;<br />
}<br />
public void insert(Object x){<br />
//insert at front;<br />
first.next=new Node(x,first.next);<br />
}<br />
hs / fub - alp2-08 13
Suchen eines Elements<br />
public boolean find (Object x){<br />
Node ptr=first.next;<br />
while ( ptr!=first) {<br />
if ( ptr.val.equals(x)) {return true;}<br />
else ptr=ptr.next;<br />
}<br />
return false;<br />
}<br />
Leere Liste? <br />
hs / fub - alp2-08 14
Wichtige Variante: Doppelt verkettete zirkuläre Liste<br />
class DLList {…<br />
public DLList(){<br />
head = new Node2();<br />
head.next=head;<br />
head.previous=head;<br />
}<br />
...<br />
}<br />
class Node2{<br />
Object val;<br />
Node2 next, previous;<br />
}<br />
Variable<br />
vom Typ<br />
DLList<br />
hs / fub - alp2-08 15
<strong>8.</strong>2 Felder<br />
Feld (array) a:<br />
Repräsentation der Werte eines Produkttyps T n <strong>mit</strong><br />
beliebigem aber gleichem Basistyp T und beliebiger aber<br />
fester natürlicher Zahl n > 0 .<br />
Java-Spezifika:<br />
- ein Feldtyp wird <strong>mit</strong> T[] bezeichnet.<br />
Bsp: double[] ist ein Feldtyp <strong>mit</strong> Basistyp Float,<br />
Point[] ist Feldtyp <strong>mit</strong> Basistyp Point (!)<br />
- Felder sind Objekte und müssen erzeugt werden.<br />
hs / fub - alp2-08 16
Erzeugung eines Felds<br />
double[] myArray = new double[4];<br />
0.0<br />
0.0<br />
0.0<br />
0.0<br />
myArray[0]<br />
myArray[3]<br />
⇒ Feldvariable hat Verweistyp.<br />
- Indexierte Feldvariable myArray[i] bezeichnet das<br />
i+1-te Feldelement (erstes: myArray[0])<br />
-Typ der Indexmenge: int oder verträglich <strong>mit</strong> int<br />
- Feldelemente werden gemäß Basistyp voreingestellt.<br />
(Autoinitialisierung)<br />
hs / fub - alp2-08 17
Initialisierung..<br />
int[] a = {3,7,2};<br />
… schließt Erzeugung ein.<br />
Man vermutet, dass<br />
vom Übersetzer<br />
initialisiert wird -<br />
<strong>mit</strong>nichten! Also <strong>auf</strong>wändig!<br />
Zuweisung …<br />
int[] b = a;<br />
… erzeugt keine Kopie<br />
Zuweisung…<br />
short[] s={4,6,5};<br />
int[] f = s;<br />
nicht erlaubt, obwohl short <strong>mit</strong> int verträglich.<br />
Warum??<br />
a<br />
b<br />
…<br />
hs / fub - alp2-08 18
Kein Feld:<br />
Point [] pFeld;<br />
null<br />
Leeres Feld:<br />
Point [] pFeld = new Point[0];<br />
Kein leeres Feld<br />
Nicht zu gebrauchen…<br />
Point [] pF = new Point[4];<br />
pF<br />
null nullnull null<br />
Feldelemente sind Objektverweise vom Typ Point.<br />
hs / fub - alp2-08 19
Traversieren von Feldern<br />
int[] f = new int[10];<br />
for(int i = 0; i=<br />
ArrayIndexOutOfBounds<br />
f.length<br />
hs / fub - alp2-08 20
Traversieren (2)<br />
for(int i = 0; i< f.lengthi++) {<br />
if (f[i] > AVG){count++;}<br />
}<br />
kann ersetzt werden durch:<br />
for (int x: f) { //Java 1.5<br />
if (x > AVG){count++;}<br />
}<br />
Nicht immer hilfreich:<br />
for (int x: f) {<br />
x*=2;<br />
} verändert x, nicht f (!)<br />
hs / fub - alp2-08 21
Methoden (nur einige)<br />
Kopieren eines Felds f :<br />
fType a = f.clone();<br />
a enthält Verweis <strong>auf</strong> eine Kopie von f (*)<br />
Diverse Methoden in java.util.Arrays, z.B.:<br />
Vergleich zweier Felder f1,f2 gleichen Typs:<br />
boolean b = equals(f1,f2);<br />
Gleichheit ⇔ gleicher Typ und gleiche Länge und<br />
alle Elemente gleich.<br />
(*) (genauer: eine flache Kopie)<br />
aber das kann man<br />
auch selbst programmieren…<br />
hs / fub - alp2-08 22
<strong>Programmieren</strong> <strong>mit</strong> Feldern (Beispiele)<br />
Gleichheit von Feldern: equals<br />
static public boolean equals (Object[] p, Object[] q ){<br />
if (p==null || q== null) {return false;}<br />
if (p.length != q.length) {return false;}<br />
for (int i=0; i < p.length; i++){<br />
if (p[i] != q[i]){return false;}<br />
}<br />
return true;<br />
}<br />
Verglichen werden Objektverweise, nicht Objekte!<br />
hs / fub - alp2-08 23
Suchen eines Feldelements <strong>mit</strong> Wächter (sentinal):<br />
final int MAX=…;<br />
int[] a = new int[MAX+1] // a[0] bleibt leer!<br />
public boolean find (int n){<br />
a[0] = n;<br />
for (int i = a.length-1; i==0; i--){<br />
if (a[i] == n) return i!=0;<br />
}<br />
return false;<br />
}<br />
hs / fub - alp2-08 24
Polynomauswertung nach Horner:<br />
p n (x) = a n *x n +…+a 1 *x 1 + a 0 = (…( 0*x+a n )*x +a n-1 )*x +…+a 1 )*x +a 0<br />
static double horner (double x, double[] a){<br />
// a != null, a.length = n+1<br />
double p=0;<br />
for (int i=a.length-1; i==0; i--){<br />
p = p*x + a[i];<br />
}<br />
return p;<br />
}<br />
hs / fub - alp2-08 25
Mehrdimensionale Felder<br />
Beispiele:<br />
2D-Matrix : double[][] matrix = new double [100] [100];<br />
Bildpunkte: byte[][] screen = new byte [1280] [1024];<br />
Elementzugriff durch Doppelindex:<br />
for (int z = 0; z < 1280; z ++) {<br />
for (int s = 0; s < 1024; s++) {<br />
screen[z] [s] = (byte)0xff;<br />
}}<br />
hs / fub - alp2-08 26
<strong>8.</strong>4 Zeichenketten<br />
In vielen Programmiersprachen als Feld von Zeichen<br />
realisiert.<br />
Java:<br />
Klassentyp, der Standardtyp der Sprache ist.<br />
String s; ist Verweis (<strong>mit</strong> undefiniertem Wert)<br />
String h = "Hello", w = "world"; //Literale "…"<br />
sind zwei konstante(!) Zeichenketten.<br />
String hw = h+w;<br />
kopiert beide Zeichenketten und fügt die Kopien zusammen,<br />
also neues Zeichenkettenobjekt!<br />
Operation + (Konkatenation) hochgradig überladen.<br />
String s = 3 + "-mal Hello " + "world";<br />
Alle Typen werden in String bewandelt, hier int<br />
hs / fub - alp2-08 27
Beachte:<br />
int[] q = {0,1,2,3,4};<br />
int[] p = {0,1,2,3,4};<br />
boolean b = p==q; // false<br />
String s1 = "Hello";<br />
String s2 = "Hello";<br />
boolean b = s1==s2 // true(!)<br />
s1<br />
s2<br />
Hello<br />
Literal gleiche Strings werden nur<br />
einmal als Konstante gespeichert.<br />
hs / fub - alp2-08 28
Weiteres Besonderheiten … oder auch nicht:<br />
String s1 = "Hello";<br />
String s2 = new String(s1);<br />
boolean b = s1==s2; // false<br />
Hier wird also eine<br />
echte Kopie angelegt!.<br />
String s1;<br />
String s2="";<br />
if (s1!=s2) …;<br />
String s = null;<br />
String t = "";<br />
boolean b = s == t; //false<br />
Fehlermeldung des<br />
Übersetzers: nicht<br />
initialisiert.<br />
Kein Wunder,<br />
wie bei allen<br />
Verweistypen.<br />
hs / fub - alp2-08 29
Viele Operationen <strong>auf</strong> String-<strong>Objekten</strong><br />
(siehe java.lang.String)<br />
s.length()<br />
Länge der Zeichenkette x<br />
s.charAt(i)<br />
Zeichen an Position i<br />
String.valueOf(x)<br />
Zeichenkettendarstellung für beliebigen Typ<br />
(also auch vielfach überladen)<br />
s.toCharArray()<br />
Zeichenkettenfelddarstellung von s<br />
da<strong>mit</strong>:<br />
s.equals(new String(s.toCharArray())<br />
hs / fub - alp2-08 30