Programmieren mit Harald R. Haberstroh (original) (raw)

Donnerstag, 28. Mai 2015

Aufgabe JTable (POS1:3BHIF)

Erstellen Sie ein Java-Programm, welches einfache CSV-Dateien erzeugen, darstellen und ändern kann. Verwenden Sie zur Darstellung der CSV-Datei eine JTable. Beim Neuanlegen wird die Anzahl der Spalten festgelegt. Beim Laden einer CSV-Datei wird die Anzahl der Zeilen/Spalten durch die Datei gegeben. Das Programm soll es ermöglichen, jede Zelle (definiert durch Zeile und Spalte) zu ändern. Sehen Sie eine Möglichkeit zum Einfügen neuer Zeilen vor. Eine markierte Zeile soll gelöscht werden können.

Die Beschriftung der Spalten soll in der ersten Zeile der Datei gespeichert werden bzw. wird beim Laden aus der ersten Zeile der Datei entnommen.

Labels: Aufgabe, GUI, Java, POS1-3

Mittwoch, 20. Mai 2015

Berechnungen mit Threads parallelisieren (POS1: 3BHIF)

π kann mit Hilfe der folgenden Formel von Strömer (1986) berechnet werden:

π / 4 = 44 · arctan 1/57 + 7 · arctan 1/239 - 12 · arctan 1/682 + 24 · arctan 1/12943

Der Arcustangens wird mit der folgenden Reihenentwicklung

arctan(x) = x - x3/3 + x5/5 - x7/7 + ...

berechnet.

Folgendes Java-Programm verwendet die Klasse BigDecimal zur Berechnung von π. Es soll mittels Threads parallelisiert werden.

import java.math.; /*

}

Wieviele Threads sind hier sinnvoll?

Vergleich zwischen serieller und paralleler Berechnung:

Zeitmessungen unter Linux auf einem Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz (Quadcore) (Intel(R) Core(TM) i3 CPU 560 @ 3.33GHz) mit 8GB RAM. Daneben wurden eclipse und chrome verwendet.

Stellen sequentiell 4 Threads
1000 4,395s 2,530s
2000 35,814s 19,260s
3000 126,145s 65,693s
4000 321,916s 163,393s
5000 626,394s 323,876s
6000 1132,480s 568,905s
7000 1800,781s 912,360s
8000 2753,654s 1462,561s
9000 3941,230s 2134,741s
10000 5527,330s 2878,974s

Bei der JVM kann man nicht bestimmen, ob und wie die Threads auf die CPUs (Kerne) aufgeteilt werden sollen. Die JVM und das Betriebssystem bestimmen, wie die Threads auf CPU-Kerne abgebildet werden. Das ist natürlich auch von der allgemeinen Systemlast abhängig.

Die Messungen zeigen, dass sich die Rechenzeit bei 4 Threads halbiert. Die CPU trägt zwar im Namen "Quadcore", tatsächlich ist es aber nur ein Dualcore mit vier Threads (siehe Link oben). Das bedeutet bei dieser Anwendung, dass nur zwei Threads echt parallel laufen können (weiter geteilt mit den anderen Prozessen, die auf dem System laufen).

Labels: algorithmen, Aufgabe, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 11:54 0 Kommentare

Mittwoch, 3. Dezember 2014

Java Swing Währungsumrechner (POS1: 3BHIF)

Erstellen Sie eine Swing-GUI mit Texteingabefeldern und Labels für 5 verschiedene Währungen. Es soll ein Neu/Löschen und ein Umrechen-Button vorhanden sein.
Wenn der Umrechen-Button gedrückt wird, wird erkannt in welcher Währung die Eingabe erfolgte und diese Währung in alle anderen umgerechnet.
Der Neu/Löschen-Button löscht alle Eingaben.
Fehler wie z.B. keine Eingabe, Eingaben in mehreren Feldern, falsche Eingabe (Text statt Zahl) u.s.w. sollen zu keinem Programmabsturz führen sondern den Benutzer mit einem Fehlerdialog darauf hinweisen.

Labels: Aufgabe, GUI, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 11:02 0 Kommentare

Mittwoch, 19. November 2014

Java Grafik/GUI (POS1: 3BHIF)

Einfache Grafik

Schreiben Sie eine Klasse PaintQuadrats, welche in einem Fenster (JFrame) eine Reihe von Quadraten zeichnet, die fortlaufend nummeriert sind:

Verwenden Sie eine Liste (ArrayList oder ein Feld) von Knoten (Node), die "sich zeichnen" (paint(Graphics g)) können. In der Methode paintComponents(Graphics g) des JPanels müssen dann für alle Knoten deren paint()-Methode aufgerufen werden.

Experimente mit Swing-Komponenten

Alle Steuerelemente von Swing (javax.swing.*) und AWT können auch als sogenannte Java Beans verwendet werden und damit auch dynamisch geladen werden. Eine JavaBean besitzt immer einen Standardkonstruktor. Dies ermöglicht eine standardisierte Instanzierung (vgl. Java Beans).

Im public/3bhif/java-gui-experiments/.hg finden Sie ein Mercurial Repository, welches ein Eclipse-Projekt mit den nötigen Klassen für die folgenden Beispiele enthält. Sie können in der Schule das Repository einfach klonen:

$ hg clone /home/teachers/hp/public/3bhif/java-gui-experiments Zielverzeichnis: java-gui-experiments Aktualisiere auf Zweig default 25 Dateien aktualisiert, 0 Dateien zusammengeführt, 0 Dateien entfernt, 0 Dateien ungelöst $

Damit wird im aktuellen Verzeichnis ein Projektverzeichnis java-gui-experiments erzeugt.
Das Projekt wird eventuell um neue Klassen ergänzt. Sie können sich die Änderungen holen:

$ cd java-gui-experiments $ hg pull /home/teachers/hp/public/3bhif/java-gui-experiments Hole von /home/teachers/hp/public/3bhif/java-gui-experiments Suche nach Änderungen Keine Änderungen gefunden $

Sollten Sie nicht auf einem Schul-PC das Repository klonen wollen, dann müssen Sie das Verzeichnis erst "mounten" und dann klonen:

$ mkdir ~/edvossh $ sshfs user@edvossh.htlwrn.ac.at:/home/teachers/hp/public/3bhif ~/edvossh $ hg clone ~/edvossh/java-gui-experiments Zielverzeichnis: java-gui-experiments Aktualisiere auf Zweig default 25 Dateien aktualisiert, 0 Dateien zusammengeführt, 0 Dateien entfernt, 0 Dateien ungelöst $

**user** ist natürlich mit Ihrem Usernamen in der Schule zu ersetzen. Die Eingabe des Passworts ist in obigen Beispielen nicht angezeigt,
Neue Versionen bekommen Sie sinngemäß mit hg pull ins lokale Repository.
Zurück zu den Steuerelementen/JavaBeans.
Im Projekt java-gui-experiments/bin können Sie Klassen nun aufrufen. Ein Beispiel zum Demonstrieren eines JButtons mit der Beschriftung "Hello World!" in einer 48 Punkt Schriftart:

$ cd java-gui-experiments/bin/ $ java je3.gui.ShowBean javax.swing.JButton 'text=Hello World!' font=helvetica-bold-48

Das sieht etwa folgendermaßen aus:

Sie können auch mehrere Steuerelemente auf der Kommandozeile angeben. Z.B.:

$ cd java-gui-experiments/bin/ $ java je3.gui.ShowBean javax.swing.JButton 'text=Hello World!' font=helvetica-bold-48
javax.swing.JRadioButton 'text=pick me'
java.awt.Button label=Hello javax.swing.JSlider

Experimentieren Sie mit weiteren Steuerelementen (Lesson: Getting Started with Swing).

Experimentieren Sie mit folgender Klasse. Sie zeigt die Verschachtelung verschiedener Container:

package je3.gui; import javax.swing.; import java.awt.;

/**

*/ public class Containers extends JPanel { public Containers( ) { this.setBackground(Color.white); // This component is white this.setFont(new Font("Dialog", Font.BOLD, 24));

    JPanel p1 = new JPanel( );
    p1.setBackground(new Color(200, 200, 200)); // Panel1 is darker
    this.add(p1);                // p1 is contained by this component
    p1.add(new JButton("#1"));   // Button 1 is contained in p1
    
    JPanel p2 = new JPanel( );
    p2.setBackground(new Color(150, 150, 150)); // p2 is darker than p2
    p1.add(p2);                  // p2 is contained in p1
    p2.add(new JButton("#2"));   // Button 2 is contained in p2
    
    JPanel p3 = new JPanel( );
    p3.setBackground(new Color(100, 100, 100)); // p3 is darker than p2
    p2.add(p3);                  // p3 is contained in p2
    p3.add(new JButton("#3"));   // Button 3 is contained in p3
    
    JPanel p4 = new JPanel( );
    p4.setBackground(new Color(150, 150, 150)); // p4 is darker than p1
    p1.add(p4);                  // p4 is contained in p1
    p4.add(new JButton("#4"));   // Button4 is contained in p4
    p4.add(new JButton("#5"));   // Button5 is also contained in p4
    
    this.add(new JButton("#6")); // Button6 is contained in this component
}

}

Starten/verwenden kann man diese Klasse mit:

$ cd java-gui-experiments/bin/ $ java je3.gui.ShowBean je3.gui.Containers

Im package je3.gui finden Sie ein paar Klassen *Layout*, welche die verschiedenen Layoutmanager demonstrieren. Dokumentation finden Sie hier: Lesson: Laying Out Components Within a Container

Ein Beispiel für das GroupLayout finden Sie in layout.Find, welches etwa so aussieht:

Verwenden Sie diese Beispiele als Basis für eigene Projekte!

Labels: Aufgabe, GUI, Java, POS1-3, User Interface

# Eingestellt von Harald R. Haberstroh @ 11:22 0 Kommentare

Mittwoch, 8. Oktober 2014

Musterlösung zu Unit-Tests

Musterlösung zur Aufgabe zu Unit-Tests

Folgende Grenzfälle werden getestet:

Sonderfälle:

"Normalfälle":

Weitere Annahmen, die aus der Angabe nicht unbedingt hervorgehen:
Die Artikel (Elemente/Items) werden in der Reihenfolge und der gegebenen Anzahl gespeichert, als addItems() aufgerufen wurde. Wird ein Element mit der Anzahl 5 in den Warenkorb aufgenommen, so wird das Element 5 mal gespeichert.

Testklasse:
Die Kommentare wurden für diesen Beitrag weggelassen, da die Klasse ohnedies schon sehr lange ist.

import java.util.Iterator; import junit.framework.TestCase;

public class ShoppingCartTest extends TestCase {

private ShoppingCart cart;
private ItemCount itemCount;

private Item[] items = { new Item(1), new Item(2), new Item(3) };

protected void setUp() throws Exception {
    cart = new MyCart();
    itemCount = (ItemCount) cart;
}

protected void tearDown() throws Exception {
}

public void testAddItems0() {
    try {
        cart.addItems(items[0], 0);
        assertEquals("testDeleteItems0: 0 Elemente", 0, cart.itemCount());
    } catch (NegativeCountException e) {
        fail("testAddItem0: es dürfte keine NegativeCountException"
             + " geworfen werden");
    }
}

public void testAddItemNegativ() {
    try {
        cart.addItems(items[0], -23);
        fail("testAddItemNegativ: es müsste eine NegativeCountException"
             + " geworfen werden");
    } catch (NegativeCountException e) {
    }
}

public void testDeleteItems0() {
    try {
        cart.addItems(items[0], 1);
        cart.deleteItems(items[0], 0);
        assertEquals("testDeleteItems0: 1 Element", 1, cart.itemCount());
    } catch (NegativeCountException e) {
        fail("testDeleteItems0: es dürfte keine NegativeCountException"
             + " geworfen werden");
    } catch (NoSuchItemException e) {
        fail("testDeleteItems0: es dürfte keine NoSuchItemException"
             + " geworfen werden");
    }
}

public void testDeleteItemsNoSuchItem() {
    try {
        cart.addItems(items[0], 1);
        cart.deleteItems(items[1], 1);
        fail("testDeleteItemsNoSuchItem: es müsste NoSuchItemException"
             + " geworfen werden");
    } catch (NegativeCountException e) {
        fail("testDeleteItemsNoSuchItem: es dürfte keine" 
             + " NegativeCountException geworfen werden");
    } catch (NoSuchItemException e) {
        assertEquals("testDeleteItemsNoSuchItem: 1 Element", 1,
                cart.itemCount());
    }
}

public void testDeleteItemNegativ() {
    try {
        cart.addItems(items[0], 2);
        cart.deleteItems(items[0], -23);
        fail("testAddItemNegativ: es müsste eine NegativeCountException"
             + " geworfen werden");
    } catch (NegativeCountException e) {
    } catch (NoSuchItemException e) {
        fail("testAddItemNegativ: es dürfte keine NoSuchItemException"
             + " geworfen werden");

} }

public void testAddItems10() {
    try {
        cart.addItems(items[0], 3);
        cart.addItems(items[1], 3);
        cart.addItems(items[2], 4);
        assertEquals("testAddItems10: 10 Elemente", 10, cart.itemCount());
    } catch (NegativeCountException e) {
        fail("testAddItems10: es dürfte keine NegativeCountException"
             + " geworfen werden");
    }
}

public void testAddDeleteItems5() {
    try {
        cart.addItems(items[0], 3);
        cart.addItems(items[1], 3);
        cart.addItems(items[2], 4);
        cart.deleteItems(items[0], 2);
        cart.deleteItems(items[2], 2);
        cart.deleteItems(items[1], 1);
        assertEquals("testAddDeleteItems5: 5 Elemente", 5, cart.itemCount());
    } catch (NegativeCountException e) {
        fail("testAddDeleteItems5: es dürfte keine NegativeCountException"
             + " geworfen werden");
    } catch (NoSuchItemException e) {
        fail("testAddDeleteItems5: es dürfte keine NoSuchItemException"
             + " geworfen werden");
    }
}

public void testIterator() {
    try {
        cart.addItems(items[0], 3);
        cart.addItems(items[1], 3);
        cart.addItems(items[2], 4);
        Iterator<Item> iterator = cart.iterator();
        int cntItems = 0;
        Item[] stroredItems = new Item[10];
        while (iterator.hasNext()) {
            stroredItems[cntItems] = iterator.next();
            cntItems++;
        }
        assertEquals("testIterator: 10 Elemente", 10, cntItems);
        for (int i = 0; i < 3; i++) {
            assertEquals("testIterator: Element sollte gleich sein",
                    items[0], stroredItems[i]);
            System.out.println(stroredItems[i]);
        }
        for (int i = 3; i < 6; i++) {
            assertEquals("testIterator: Element sollte gleich sein",
                    items[1], stroredItems[i]);
            System.out.println(stroredItems[i]);
        }
        for (int i = 6; i < 10; i++) {
            assertEquals("testIterator: Element sollte gleich sein",
                    items[2], stroredItems[i]);
            System.out.println(stroredItems[i]);
        }
    } catch (NegativeCountException e) {
        fail("testIterator: es dürfte keine NegativeCountException"
             + " geworfen werden");
    }
}

public void testItemCount() {
    try {
        cart.addItems(items[0], 3);
        cart.addItems(items[1], 3);
        cart.addItems(items[0], 1);
        cart.addItems(items[2], 4);
        cart.addItems(items[0], 2);
        assertEquals("testItemCount: Anzahl falsch", 6,
                itemCount.itemCount(items[0]));
        assertEquals("testItemCount: Anzahl falsch", 3,
                itemCount.itemCount(items[1]));
        assertEquals("testItemCount: Anzahl falsch", 4,
                itemCount.itemCount(items[2]));
    } catch (NegativeCountException e) {
        fail("testItemCount: es dürfte keine NegativeCountException"
             + " geworfen werden");
    } catch (NoSuchItemException e) {
        fail("testItemCount: es dürfte keine NoSuchItemException"
             + " geworfen werden");
    }
}

public void testItemCountNosuchItem() {
    @SuppressWarnings("unused")
    int cnt;
    try {
        cnt = itemCount.itemCount(items[0]);
        fail("testItemCountNosuchItem: es müsste eine NoSuchItemException"
             + " geworfen werden");
    } catch (NoSuchItemException e) {
    }
    try {
        cart.addItems(items[1], 3);
        cnt = itemCount.itemCount(items[0]);
        fail("testItemCountNosuchItem: es müsste eine NoSuchItemException"
             + " geworfen werden");
    } catch (NegativeCountException e) {
        fail("testItemCountNosuchItem: es dürfte keine"
             + " NegativeCountException geworfen werden");
    } catch (NoSuchItemException e) {
    }
}

}

Implementierung des Interfaces ShoppingCart:
Zusätzlich zur originalen Aufgabenstellung wurde noch folgendes Interface implementiert, damit man einfach die Anzahl eines bestimmten Items bestimmen kann:

public interface ItemCount { public int itemCount(Item anItem) throws NoSuchItemException; }

Zur Speicherung der Items wird einfach eine ArrayList verwendet.

import java.util.ArrayList; import java.util.Iterator;

public class MyCart implements ShoppingCart, ItemCount {

private ArrayList<Item> items = new ArrayList<Item>();

public void addItems(Item anItem, int quantity)
        throws NegativeCountException {
    if (quantity < 0) {
        throw new NegativeCountException();
    }
    for (int i = 0; i < quantity; i++) {
        items.add(anItem);
    }
}

public void deleteItems(Item anItem, int quantity)
        throws NegativeCountException, NoSuchItemException {
    if (quantity < 0) {
        throw new NegativeCountException();
    }
    for (int i = 0; i < quantity; i++) {
        if (!items.remove(anItem))
            throw new NoSuchItemException();
    }
}

public int itemCount() {
    return items.size();
}

public Iterator<Item> iterator() {
    return items.iterator();
}

@Override
public int itemCount(Item anItem) throws NoSuchItemException {
    int cnt = 0;
    if (!items.contains(anItem)) {
        throw new NoSuchItemException();
    }
    for (Item item : items) {
        if (item == anItem) {
            cnt++;
        }
    }
    return cnt;
}

}

Weiters müssen natürlich die geforderten Exceptions implementiert werden (Kommentare wurden auch hier weggelassen):

public class NegativeCountException extends Exception { }

public class NoSuchItemException extends Exception { }

Die Klasse für die Artikel (Item) wurde einfach durch eine Nummer ergänzt, die beim Konstruktor angegeben werden muss. Für eine realistische Anwendung müsste diese Klasse noch erweitert werden:

public class Item { private int itemNr = 0;

public Item(int itemNr) { this.itemNr = itemNr; }

@Override public String toString() { return "Item " + itemNr; } }

Labels: Java, Lösung, POS1-3, Testen

# Eingestellt von Harald R. Haberstroh @ 11:48 0 Kommentare

Mittwoch, 4. Dezember 2013

Java Console mit eclipse

Java bietet seit Version 1.6 eine einfachere Methode (als java.io.BufferedReader) von der Konsole zu lesen: java.io.Console. Leider kann Console nicht innerhalb von eclipse verwendet werden, da sich diese Entwicklungsumgebung direkt mit der Ein- und Ausgabe verbindet.

Es gibt eine - etwas umständliche - Lösung dieses Problems, die hier auf stackoverflow.com beschrieben wird.

Hier eine für eclipse unter Linux adaptierte Variante. Nehmen wir an, die folgende Klasse, soll mit dem Debugger getestet werden:

import java.io.Console; public class TestDebugging { public static void main(String[] args) { Console console = System.console(); if (console != null) { String line = console.readLine(">>> "); System.out.println(line); } else { System.err.println("sorry, no console available!"); } } }

Startet man diese Klasse in eclipse (egal ob "Run" oder "Debug"), dann wird immer "sorry, no console available!" angezeigt. Startet man die Klasse in einem Terminal, so funktioniert sie problemlos:

hp@if211l $ java TestDebugging

test test hp@if211l $

Das Prinzip

Man muss das Java-Programm in einem Terminal starten und sich mit eclipse "remote" verbinden. Dazu verwendet man für den Start der Klasse folgenden Aufruf:

hp@if211l $ java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y TestDebugging Listening for transport dt_socket at address: 8787

Java wartet (suspend=y) nun darauf, dass man sich mit dem Debugger über Port 8787 (address=8787) hin verbindet. Im eclipse ruft man dann bei geöffnetem Sourcecode der Klasse "Run>Debug Configurations" auf und legt eine neue "Remote Java Application" an.

Nachdem man (sinnvollerweise) einen Breakpoint gesetzt hat, kann man diese Debug-Konfiguration aufrufen und die Klasse debuggen. Die Ein- und Ausgabe erfolgt dann im Terminal:

Umsetzung

Um die Sache etwas komfortabler zu machen, sollte man folgendes Shell-Script erstellen:

#!/bin/bash

launch java for external debugging

export D_PORT=8787 export D_DBG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,
address=${D_PORT},server=y,suspend=y" x-terminal-emulator -x java DDBG−cp./bin/{D_DBG} -cp ./bin/ DDBGcp./bin/1 &

Dieses Script kann nun unter "Run>External Tools Configuration" eingerichtet werden:

Das Script startet ein Terminal-Fenster (x-terminal-emulator -x) mit dem entsprechenden Java-Aufruf (java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y).

Debugging funktioniert wie oben beschrieben, indem man "Remote Java Application" verwendet.

Labels: eclipse, Java, POS1-2, POS1-3, POS1-4

# Eingestellt von Harald R. Haberstroh @ 13:11 0 Kommentare

Donnerstag, 23. Mai 2013

Graph Algorithms (POS1:3BHIF)

Erstellen Sie ein Java-Programm zum Zeichnen von gerichteten Graphen. Das folgende Bild zeigt ein mögliches User-Interface.

Anforderungen

Die Nummerierung dient nur, um auf die einzelnen Anforderungen zu referenzieren.

  1. Anlegen von Knoten - Knoten sollen durch einfachen Klick auf die leere Zeichenfläche angelegt werden. Die Beschriftung soll automatisch erfolgen (A, B, C, ...). Die Knoten dürfen sich nicht überlappen.
  2. Anlegen von gerichteten Kanten - durch Ziehen mit der rechten Maustaste soll eine Kante von einem Knoten zu einem anderen Knoten gezeichnet werden können (gerade Linie mit Pfeilspitze). Alternativ kann die linke Maustaste mit gedrückter Strg-Taste verwendet werden.
  3. Die Gewichtung einer Kante soll eingegeben werden können.
  4. Die Gewichtung einer Kante soll geändert werden können.
  5. Knoten sollen durch ziehen verschoben werden können (linke Maustaste), die Kanten von/zu diesem Knoten müssen entsprechend neu gezeichnet werden können. Die Knoten dürfen sich nicht überlappen!
  6. Knoten sollen (de-)selektiert/markiert werden können (Mausklick). Markierung/Selektion soll umgeschaltet werden (toggle).
  7. Kanten sollen (de-)selektiert/markiert werden können (Mausklick). Markierung/Selektion soll umgeschaltet werden (toggle).
  8. Markierte Elemente sollen gelöscht werden können (Menüpunkt, Shortcut Entf).
  9. Ein Graph soll in einer Datei gespeichert werden können.
  10. Ein Graph soll aus einer Datei geladen werden können.
  11. Die Zeichenfläche soll gelöscht werden können.
  12. Im Hilfemenü soll eine Infobox mit Ihrem Namen, der Klasse und dem Erstellungsjahr aufgerufen werden können.
  13. Optional: Eine Hilfe zur Bedienung (Dialogfenster mit HTML-Text).
  14. Optional: Die Sprache soll geändert werden können (Englisch, Deutsch, weitere mit Sprachdateien). Standard ist die Systemeinstellung.
  15. Scrollbars sollen eingeblendet werden, wenn das Fenster kleiner als die benötigte Zeichenfläche ist.
  16. Ein Graph soll gedruckt werden können. Gegebenenfalls auf eine Seite skalieren.
  17. Simulation der Tiefensuche - Ist ein Knoten markiert, so soll die Tiefensuche beginnend nur mit diesem Knoten durchgeführt werden und die einzelnen Schritte dargestellt werden (weiß/grau/schwarz). Ist kein Knoten markiert, so soll der Algorithmus auf alle Knoten angewendet werden.
    Verwenden Sie dazu einen Thread.
  18. Simulation der Breitensuche - Ist ein Knoten markiert, so soll die Breitensuche beginnend nur mit diesem Knoten durchgeführt werden und die einzelnen Schritte dargestellt werden (weiß/grau/schwarz). Ist kein Knoten markiert, so soll der Algorithmus auf alle Knoten angewendet werden.
    Verwenden Sie dazu einen Thread.
  19. Optional: Die Simulation(en) sollen abgebrochen werden können.
  20. Optional: Es soll eine undo/redo-Funktionalität implementiert werden (Command Pattern).
  21. Das Programm soll als "ausführbare" Jar-Datei geliefert werden, d.h. alle nötigen Klassen, Bibliotheken, Grafiken und Konfigurationsdateien (Sprachdateien) sollen sich in dem Jar-Archiv befinden. Aufruf soll nur über java -jar graph.jar möglich sein (meist kann man die graphische Oberfläche so einstellen, dass ein Klick auf die Datei genügt).

Literatur

Labels: algorithmen, Aufgabe, GUI, Java, POS1-3, User Interface

# Eingestellt von Harald R. Haberstroh @ 10:45 0 Kommentare

Donnerstag, 7. März 2013

Deadlocks (POS1: 3BHIF)

Implementieren Sie in Java eine Simulation des Philosophenproblems (Aufgabenstellung über den Link).

Zeigen Sie das Auftreten eines Deadlocks.

Entwickeln Sie eine Lösung ohne Deadlock.

Labels: algorithmen, Aufgabe, Informatik, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 09:01 0 Kommentare

Mittwoch, 27. Februar 2013

Berechnungen mit Threads parallelisieren (POS1: 3BHIF)

π kann mit Hilfe der folgenden Formel von Strömer (1986) berechnet werden:

π / 4 = 44 · arctan 1/57 + 7 · arctan 1/239 - 12 · arctan 1/682 + 24 · arctan 1/12943

Der Arcustangens wird mit der folgenden Reihenentwicklung

arctan(x) = x - x3/3 + x5/5 - x7/7 + ...

berechnet.

Folgendes Java-Programm verwendet die Klasse BigDecimal zur Berechnung von π. Es soll mittels Threads parallelisiert werden.

import java.math.; /*

}

Wieviele Threads sind hier sinnvoll?

Vergleich zwischen serieller und paralleler Berechnung:

Zeitmessungen unter Linux auf einem Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz (Quadcore) (Intel(R) Core(TM) i3 CPU 560 @ 3.33GHz) mit 8GB RAM. Daneben wurden eclipse und chrome verwendet.

Stellen sequentiell 4 Threads
1000 4,395s 2,530s
2000 35,814s 19,260s
3000 126,145s 65,693s
4000 321,916s 163,393s
5000 626,394s 323,876s
6000 1132,480s 568,905s
7000 1800,781s 912,360s
8000 2753,654s 1462,561s
9000 3941,230s 2134,741s
10000 5527,330s 2878,974s

Bei der JVM kann man nicht bestimmen, ob und wie die Threads auf die CPUs (Kerne) aufgeteilt werden sollen. Die JVM und das Betriebssystem bestimmen, wie die Threads auf CPU-Kerne abgebildet werden. Das ist natürlich auch von der allgemeinen Systemlast abhängig.

Die Messungen zeigen, dass sich die Rechenzeit bei 4 Threads halbiert. Die CPU trägt zwar im Namen "Quadcore", tatsächlich ist es aber nur ein Dualcore mit vier Threads (siehe Link oben). Das bedeutet bei dieser Anwendung, dass nur zwei Threads echt parallel laufen können (weiter geteilt mit den anderen Prozessen, die auf dem System laufen).

Labels: algorithmen, Aufgabe, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 22:45 0 Kommentare

Einführung in die O-Notation (Big O Notation)

Dies ist eine Mini-Einführung in die O-Notation. Wer es genau wissen will, soll gleich unten bei der Literaturliste bzw. den Links weitermachen.

Die O-Notation (engl. Big O Notation) wird in der Informatik zu Beschreibung der Komplexität (und damit der Laufzeit) eines Algorithmus. Die O-Notation beschreibt den schlechtesten Fall (worst-case scenario). Sie beschreibt die Ausführungszeit oder den Speicheraufwand, den ein Algorithmus benötigt.

Alle, die Programming Pearls (Programming Pearls (ACM Press)) oder irgend ein anderes Informatik Buch lesen und kein fundiertes mathematisches Wissen haben, werden sich den Kopf stoßen, sobald sie Kapitel erreichen, in denen so komische Dinge wie O(N log N) vorkommen. Ich hoffe, dieser Beitrag wird zu einem besseren Verständnis der Grundlagen zur O-Notation verhelfen.

Für Programmierer sind wahrscheinlich kurze Code-Beispiele am Besten geeignet die O-Notation zu verstehen. Die Beispiele zeigen die übliche Reihenfolge der Komplexität, von einfachen bis zu aufwendigen Beispielen.

O(1)

O(1) beschreibt einen Algorithmus, der immer die selbe Zeit (oder den selben Speicher) benötigt, unabhängig von der Größe der Eingabedaten.

boolean isFirstElementNull(String[] strings) { if (strings[0] == null) { return true; } return false; }

Es ist (hoffentlich) offensichtlich, dass diese Funktion immer gleich lange braucht, egal wie groß das String-Array ist (Außer natürlich, wenn strings == null oder strings.length == 0 ist, denn da kommt es zu einer Exception! Diese Sonderfälle lassen wir weg.).

O(N)

O(N) beschreibt Algorithmen, deren Laufzeit linear in direkter Proportionalität zur Größe des Eingabedatensatzes wachsen (z.B. dreimal so große Eingabe bewirkt eine dreimal so lange Laufzeit). Das folgende Beispiel zeigt auch, dass die O-Notation den schlechtesten (worst-case) Fall beschreibt. Die gesuchte Zahl kann natürlich in jedem Schleifendurchlauf gefunden werden und die Funktion frühzeitig beenden, aber die O-Notation beschreibt die obere Grenze, bei der die maximale Anzahl Schleifendurchläufe benötigt wird.

boolean containsValue(int[] values, int value) { for (int i = 0; i < values.length; i++) { if (value == values[i]) { // always the same time! return true; } } return false; }

O(N2)

O(N2) repräsentiert Algorithmen, deren Laufzeit direkt proportional zum Quadrat der Größe des Eingabedatensatzes sind. Das ist üblicherweise bei verschachtelten Schleifen der Fall. Tiefer verschachtelte Schleifen resultieren demnach in O(N3), O(N4) etc.

boolean containsDuplicates(int[] values) { for (int i = 0; i < values.length; i++) { for (int j = 0; j < values.length; j++) { if (i == j) { // don't compare self continue; } if (values[i] == values[j]) { return true; } } } return false; }

O(2N)

O(2N) beschreibt Algorithmen, deren Laufzeit sich für jedes weitere Element der Eingabedaten verdoppelt. Die Ausführungszeit einer O(2N) Funktion wird sehr schnell sehr groß. Das folgende Beispiel zeigt einen Algorithmus, der alle möglichen Zeichenfolgen eines Strings liefert (permutiert). Permutationen sind üblicherweise exponentiell (allgemein O(kN) für ein bestimmtes k).

public static void permutation(String str) { permutation("", str); }

private static void permutation(String prefix, String str) { int n = str.length(); if (n == 0) { System.out.println(prefix); } else { for (int i = 0; i < n; i++) { permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n)); } } }

Primzahlenbestimmung hat auch exponentiellen Aufwand (O(kN)).

Logarithmus O(log N)

Ich werde logarithmisches Verhalten an einem üblichen Beispiel erklären:

Denken Sie an ein Telefonbuch, welches Einträge sortiert nach Name, Vorname und Adresse (in dieser Reihenfolge) enthält. Wie würde man die Suche nach der Telefonnummer eines bestimmten Teilnehmers mit gegebenem Namen programmieren? Nehmen wir an, das Telefonbuch hätte 1.000.000 Einträge.

Wenn man linear sucht, dann ist der Aufwand O(N), also maximal 1.000.000 Schleifendurchläufe (im Durchschnitt 500.000). Geschickter ist jedoch die Binäre Suche, bei der man zunächst den 500.000 Eintrag nimmt und prüft. Ist das der gesuchte Name, dann ist man fertig. Ist der gesuchte Name größer (also alphabetisch weiter hinten), dann teilt man die obere Hälfte wieder in zwei Teile und vergleicht mit dem mittleren Eintrag (750.000). Ist der Eintrag nun größer als der gesuchte, dann teilt man die untere Hälfte und nimmt die Mitte ((750.000 - 500.000) / 2 + 500.000 = 625.000) usw. Nach spätestens 20 Teilungen hat man den Namen gefunden (oder er ist nicht im Telefonbuch).

Bei 3 Einträgen benötigt man höchstens 2 Schritte, bei 7 höchstens 3, bei 15 höchstens 4, bei 1000 höchstens 10 und bei 1.000.000 höchstens 20 Schritte.

Der Aufwand ist also O(log N), wobei es egal ist, welche Basis man für den Logarithmus nimmt, weil sich die Logarithmen nur durch Konstante unterscheiden, welche man bei der O-Notation weglassen kann. Die O-Notation gilt nämlich nur für große Werte von N, so dass sich Konstante praktisch nicht mehr auswirken. Die binäre Suche hat eigentlich den Aufwand von log2 N, welcher sich nur durch den konstanten Wert log 2 (Logarithmus von 2) unterscheidet.

// nums ... sorted array public static int binarySearch(int[] nums, int check) { int hi = nums.length - 1; int lo = 0; while (hi >= lo) { guess = lo + ((hi - lo) / 2); if (nums[guess] > check) { hi = guess - 1; } else if (nums[guess] < check) { lo = guess + 1; } else { return guess; } } return -1; }

Obiges Beispiel zeigt die binäre Suche mit einem sortierten int-Arrays nums und der zu suchenden Zahl check. Zurückgeliefert wird der Index oder -1, wenn die Zahl nicht in dem Array vorkommt.

Der log N ist die Umkehrung von 10N und log2 N die Umkehrung von 2N.

Es gilt:

O(1) < O(log N) < O(N) < O(N log N) < O(N2) < O(N3) < O(kN)

Quellen

Jon Bentley: Programming Pearls
Binäre Suche (Wikipedia)
Donald E. Knuth: The Art of Computer Programming
BIG-O Notation
Plain English explanation of Big O
Big O, how do you calculate/approximate it?
A Beginner’s Guide to Big O Notation

Labels: algorithmen, Informatik, POS1-2, POS1-3

# Eingestellt von Harald R. Haberstroh @ 19:44 0 Kommentare

Mittwoch, 20. Februar 2013

JTable (POS1: 3BHIF)

Erstellen Sie ein Java-Programm, welches einfache CSV-Dateien erzeugen, darstellen und ändern kann. Verwenden Sie zur Darstellung der CSV-Datei eine JTable. Beim Neuanlegen wird die Anzahl der Spalten festgelegt. Beim Laden einer CSV-Datei wird die Anzahl der Zeilen/Spalten durch die Datei gegeben. Das Programm soll es ermöglichen, jede Zelle (definiert durch Zeile und Spalte) zu ändern. Sehen Sie eine Möglichkeit zum Einfügen neuer Zeilen vor. Eine markierte Zeile soll gelöscht werden können.

Labels: Aufgabe, GUI, Java, POS1-3, User Interface

# Eingestellt von Harald R. Haberstroh @ 20:24 0 Kommentare

Mittwoch, 16. Januar 2013

Java zeichnen mit Swing (POS1: 3BHIF)

Abgabename: 2012_3bhif_aufgabe6_ Name_Vorname.tgz

Vervollständigen Sie die Zeichen-Applikation aus der letzten Aufgabe so, dass das hier ersichtliche Verhalten ermöglicht wird (Sie benötigen ein Java-Plugin für den Browser):

Hier ist GraphApplet.class

Das Applet ist nicht perfekt, aber die wichtigste Funktionalität ist vorhanden.

  1. Linke Maustaste zum Erzeugen und verschieben von Knoten.
  2. Mittlere Maustaste zum Löschen von Knoten.
  3. Rechte Maustaste (ziehen) zum Zeichnen von Kanten zwischen den Knoten.

Beachten Sie, dass sich Knoten nicht überlappen dürfen.
Das Fenster soll ein Menü mit File und Help haben.
Im File-Menü sollen folgende Funktionen ausgewählt werden können:

Das Help-Menu soll einen Eintrag mit About haben, mit dem ein Info-Dialog geöffnet werden soll. Dieser Dialog soll Name, Klasse, eine Kurzbeschreibung des Programmes und eine Versionsnummer enthalten.

Erstellen Sie eine Liste der (Teil-)Aufgaben und schätzen Sie den Aufwand.
Stellen Sie sich Fragen wie:

Labels: Aufgabe, GUI, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 17:40 0 Kommentare

Mittwoch, 9. Januar 2013

Java Grafik/GUI (POS1: 3BHIF)

Einfache Grafik

Schreiben Sie eine Klasse PaintQuadrats, welche in einem Fenster (JFrame) eine Reihe von Quadraten zeichnet, die fortlaufend nummeriert sind:

Verwenden Sie eine Liste (ArrayList oder ein Feld) von Knoten (Node), die "sich zeichnen" (paint(Graphics g)) können. In der Methode paintComponents(Graphics g) des JPanels müssen dann für alle Knoten deren paint()-Methode aufgerufen werden.

Experimente mit Swing-Komponenten

Alle Steuerelemente von Swing (javax.swing.*) und AWT können auch als sogenannte Java Beans verwendet werden und damit auch dynamisch geladen werden. Eine JavaBean besitzt immer einen Standardkonstruktor. Dies ermöglicht eine standardisierte Instanzierung (vgl. Java Beans).

Im public/3bhif/java-gui-experiments/.hg finden Sie ein Mercurial Repository, welches ein Eclipse-Projekt mit den nötigen Klassen für die folgenden Beispiele enthält. Sie können in der Schule das Repository einfach klonen:

$ hg clone /home/teachers/hp/public/3bhif/java-gui-experiments Zielverzeichnis: java-gui-experiments Aktualisiere auf Zweig default 25 Dateien aktualisiert, 0 Dateien zusammengeführt, 0 Dateien entfernt, 0 Dateien ungelöst $

Damit wird im aktuellen Verzeichnis ein Projektverzeichnis java-gui-experiments erzeugt.
Das Projekt wird eventuell um neue Klassen ergänzt. Sie können sich die Änderungen holen:

$ cd java-gui-experiments $ hg pull /home/teachers/hp/public/3bhif/java-gui-experiments Hole von /home/teachers/hp/public/3bhif/java-gui-experiments Suche nach Änderungen Keine Änderungen gefunden $

Sollten Sie nicht auf einem Schul-PC das Repository klonen wollen, dann müssen Sie das Verzeichnis erst "mounten" und dann klonen:

$ mkdir ~/edvossh $ sshfs user@edvossh.htlwrn.ac.at:/home/teachers/hp/public/3bhif ~/edvossh $ hg clone ~/edvossh/java-gui-experiments Zielverzeichnis: java-gui-experiments Aktualisiere auf Zweig default 25 Dateien aktualisiert, 0 Dateien zusammengeführt, 0 Dateien entfernt, 0 Dateien ungelöst $

**user** ist natürlich mit Ihrem Usernamen in der Schule zu ersetzen. Die Eingabe des Passworts ist in obigen Beispielen nicht angezeigt,
Neue Versionen bekommen Sie sinngemäß mit hg pull ins lokale Repository.
Zurück zu den Steuerelementen/JavaBeans.
Im Projekt java-gui-experiments/bin können Sie Klassen nun aufrufen. Ein Beispiel zum Demonstrieren eines JButtons mit der Beschriftung "Hello World!" in einer 48 Punkt Schriftart:

$ cd java-gui-experiments/bin/ $ java je3.gui.ShowBean javax.swing.JButton 'text=Hello World!' font=helvetica-bold-48

Das sieht etwa folgendermaßen aus:

Sie können auch mehrere Steuerelemente auf der Kommandozeile angeben. Z.B.:

$ cd java-gui-experiments/bin/ $ java je3.gui.ShowBean javax.swing.JButton 'text=Hello World!' font=helvetica-bold-48
javax.swing.JRadioButton 'text=pick me'
java.awt.Button label=Hello javax.swing.JSlider

Experimentieren Sie mit weiteren Steuerelementen (A Visual Guide to Swing Components).

Experimentieren Sie mit folgender Klasse. Sie zeigt die Verschachtelung verschiedener Container:

package je3.gui; import javax.swing.; import java.awt.;

/**

*/ public class Containers extends JPanel { public Containers( ) { this.setBackground(Color.white); // This component is white this.setFont(new Font("Dialog", Font.BOLD, 24));

    JPanel p1 = new JPanel( );
    p1.setBackground(new Color(200, 200, 200)); // Panel1 is darker
    this.add(p1);                // p1 is contained by this component
    p1.add(new JButton("#1"));   // Button 1 is contained in p1
    
    JPanel p2 = new JPanel( );
    p2.setBackground(new Color(150, 150, 150)); // p2 is darker than p2
    p1.add(p2);                  // p2 is contained in p1
    p2.add(new JButton("#2"));   // Button 2 is contained in p2
    
    JPanel p3 = new JPanel( );
    p3.setBackground(new Color(100, 100, 100)); // p3 is darker than p2
    p2.add(p3);                  // p3 is contained in p2
    p3.add(new JButton("#3"));   // Button 3 is contained in p3
    
    JPanel p4 = new JPanel( );
    p4.setBackground(new Color(150, 150, 150)); // p4 is darker than p1
    p1.add(p4);                  // p4 is contained in p1
    p4.add(new JButton("#4"));   // Button4 is contained in p4
    p4.add(new JButton("#5"));   // Button5 is also contained in p4
    
    this.add(new JButton("#6")); // Button6 is contained in this component
}

}

Im package je3.gui finden Sie ein paar Klassen *Layout*, welche die verschiedenen Layoutmanager demonstrieren. Dokumentation finden Sie hier: Lesson: Laying Out Components Within a Container

Ein Beispiel für das GroupLayout finden Sie in layout.Find, welches etwa so aussieht:

Verwenden Sie diese Beispiele als Basis für eigene Projekte!

Labels: Aufgabe, Java, POS1-3, User Interface

# Eingestellt von Harald R. Haberstroh @ 21:15 0 Kommentare

Sonntag, 6. Januar 2013

Abgaben im Schuljahr 2012/13

Bei den Abgabenamen jjjj_ N_bhif_aufgabe_N_ name_vorname.tgz wird für das Schuljahr 2012/13 weiterhin jjjj durch 2012 ersetzt, auch wenn wir bereits das Jahr 2013 haben. Siehe auch Abgaben (POS1: 2BHIF, 3BHIF).

Sollten wir auch im Schuljahr 2013/14 kein brauchbares zentrales Repository haben, dann werden wir Dateinamen mit 2013 im Namen haben...

Labels: allgemeines, Aufgabe, POS1-2, POS1-3

# Eingestellt von Harald R. Haberstroh @ 15:36 0 Kommentare

Mittwoch, 5. Dezember 2012

Aufgabe Syntaxanalyse (POS1: 3BHIF)

Abgabename: 2012_3bhif_aufgabe5_ Name_Vorname.tgz

  1. Untersuchen Sie die Syntax einer Gleitkomma-Konstanten in Java.
  2. Konstruieren Sie dazu einen endlichen Automaten, der diese Konstanten akzeptiert.
  3. Entwicklen Sie daraus den Minimalautomaten.
  4. Ausgehend von diesem Minimalautomaten schreiben Sie ein Programm (Automat mit switch und tabellengesteuerter Automat), das eine Zeichenkette akzeptiert, falls diese eine ganzzahlige Konstante der untersuchten Programmiersprache ist.
  5. Testen Sie die Funktionsweise des Automaten (beider Implementierungen) mit Unit-Tests.

Beispiele für Gleitkommazahlen in Java:

double r = 1.e3; double s = 1.; double u = 1e3; double v = +.2; double w = -.2e-2; double x = .1; double y = -.2; double z = -123.123e-2;

Die Variablendeklarationen sollen nicht analysiert werden.

Abgabe:
Der Automat sowie der dazugehörige Minimalautomat müssen grafisch dargestellt werden (scannen Sie eine Skizze oder zeichnen Sie mit einem Grafikprogramm). Die Konstruktionsschritte müssen ebenfalls abgegeben werden. Am Besten erzeugen Sie ein PDF, welches die Automaten und die Konstruktion enthält. Sie können auch einzelne Grafiken (PNG, JPEG) abgeben. Jedenfalls muss jedes Dokument Klasse und Namen enthalten.
Diese Dokumente müssen im Projektordner enthalten sein (Versioniert!).
Geben Sie das Projekt in gewohnter Form ab.

Labels: Aufgabe, Informatik, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 17:28 0 Kommentare

Donnerstag, 29. November 2012

Einführung Objektorientiertes Programmieren

Sie finden hier ein paar Informationen zum objektorientierten Programmieren und den von uns verwendeten Begriffen:

Es folgt ein Beispiel:

Aufgabe: Finden Sie Klassen bzw. Objekte zu folgenden Begriffen: Leo, Tiger, Samurai, Elefant, Taigon, Benjamin Blümchen, Tier, Löwe
Lösung: Beim Programmieren muss man aus einer Aufgabenstellung immer wieder Objekte und Klassen identfizieren, die man zur Implementierung benötigt. Man kann z.B. alle Subjekte der Aufgabenstellung suchen und sich dazu fragen "ist das ein Objekt oder sind das viele Objekte?". In letzterem Fall hat man einen Kandidaten für eine Klasse. Sonst ist es ein Objekt. Nicht alle Objekte werden für das Programm benötigt.
Bei diesem Beispiel ist nur eine Liste von Tieren und Namen gegeben. Namen sind normalerweise Objekte, die verschiedenen Tiere sind natürlich Klassen.
Wir werden also die Klassen Tier, Tiger, Löwe und Elefant haben. Die anderen Begriffe sind konkrete Namen. Weiters können wir die "is-a" ("ist-ein") Beziehung Tiger is-a Tier, Löwe is-a Tier und Elefant is-a Tier ausmachen.
Damit ergibt sich folgendes Bild:


Kästchen mit unterstrichenen Namen stellen konkrete Objekte dar.
Die strichlierten Pfeile stellen die Instanzierung dar. Sie sind in Pfeilrichtung zu lesen: Leo ist-ein-konkreter Löwe (Leo is-instance-of Löwe) oder Samurai ist-ein-konkreter Tiger.
Die Pfeile mit Dreiecksspitzen und durchgehenden Linien stehen für die Vererbung (is-a, ist-ein), Beispielsweise Löwe ist-ein Tier (Löwe is-a Tier).

Die Klassen könnte man so implementieren (z.B. Scrapbook):

class Tier { String name; public String toString() { return name; } public void setName(String name) { this.name = name; } }

class Löwe extends Tier {

}

class Elefant extends Tier {

}

class Tiger extends Tier {

}

Löwe leo = new Löwe(); leo.setName("Leo"); Elefant benjamin = new Elefant(); benjamin.setName("Benjamin Blümchen"); Tiger samurai = new Tiger(); samurai.setName("Samurai"); Tiger taigon = new Tiger(); taigon.setName("Taigon"); System.out.println(leo); System.out.println(benjamin); System.out.println(samurai); System.out.println(taigon);

Die Ausgabe könnte so aussehen:

Leo
Benjamin Blümchen
Samurai
Taigon

In Python könnte man das Beispiel so implementieren:

class Tier: def init(self): self.name = "" def setName(self, name): self.name = name def str(self): # toString() in Java return self.name

class Loewe(Tier): pass

class Elefant(Tier): pass

class Tiger(Tier): pass

leo = Loewe() leo.setName("Leo") benjamin = Elefant() benjamin.setName("Benjamin Blümchen") samurai = Tiger() samurai.setName("Samurai") taigon = Tiger() taigon.setName("Taigon");

print(leo) print(benjamin) print(samurai) print(taigon)

Labels: Java, POS1-2, POS1-3, Python

# Eingestellt von Harald R. Haberstroh @ 09:37 0 Kommentare

Montag, 12. November 2012

Python Objekte, Aufrufstack, Klassen (POS1)

Objekte

In Python sind alle Elemente Objekte. Folgendes Beispiel enthält ein paar solche Objekte:

def fun(x): # auch ein Objekt! y = x * x return y

f2 = fun # f1 ist eine Refernz auf fun

lst = [1, 2, fun] # Liste mit 3 Objekten l2 = lst # l2 ist eine Refernz auf obige Liste

erg = fun(2) print(erg) erg = f2(3) print(erg) print(f2 == fun) print(l2 == lst) print(lst)

Folgendes Bild zeigt den Speicher, wenn das Progarmm in der Zeile 3 angelangt ist, nach dem f2(3) (ist ja fun(3)) in der Zeile 12 Aufgerufen wurde.

Sie können den Ablauf unter folgendem Link testen:objects.py

Sie sehen auf der rechten Seite die Objekte, welche Python angelegt hat. Der linke Bereich ("Frames") zeigt den Speicher, den Python für die (globalen) Variablen anlegt sowie den Speicher für die aufgerufene Funktion. Für jede Funktion wird so ein Bereich (Frame) angelegt und beim beenden wieder zerstört.

Pfeile stellen Referenzen dar. Zum Beispiel stellt der Pfeil von lst zum Listenobjekt [1, 2, fun] dar. Auch l2 ist eine Referenz zu dieser Liste.
In dieser Liste gibt es eine weitere Referenz zur Funktion fun. Funktionsnamen sind also Referenzen zu "Funktions-Objekten" (die den Code der Funktion "enthalten").

Aufrufstack

Beim folgenden Beispiel können Sie sehen, wie Frames sich bei den Aufrufen der Funktion fact() stapeln und dann in Folge wieder zerstört werden:

def fact(n): if n > 1: return n * fact(n - 1) else: return 1

f = fact(5) print(f)

Folgendes Bild zeigt die Frames, wenn das Programm die Zeile 5 erreicht (aber nicht ausgeführt) hat. Sie sehen einen Stapel von Frames. Ein Frame pro Aufruf. Diese Frames werden anschließend bei jedem return wieder zerstört. Man nennt diesen Stapel Aufrufstack:

Sie können den Ablauf unter folgendem Link testen:fact.py

Klassen

Bei Klassen handelt es sich um benutzerdefinierte Typen. D.h. es werden Typen ange- legt, für die benutzerdefinierte Methoden (also objektgebundene Funktionen) definiert werden können:

class Car: def init(self, cartype, kind, serNr): self.cartype = cartype # die Attribute type, self.kind = kind # kind und self.serNr = serNr # serNr sind in der Instanz def maxSpeed(self): if self.kind == "pickup": # Wenn Pickup, dann langsamer return 100.0 else: return 130.0

passat1 = Car("VW/Passat", "regular_car", 11142) jetta1 = Car("VW/Jetta", "small_car", 11143) ram1 = Car("Dodge/Ram", "pickup", 22242)

fleet = [passat1, jetta1, ram1] # Fuhrpark for car in fleet: print(car.cartype, car.maxSpeed(), "km/h")

Mittels der Anweisung class wird ein neuer Typ definiert. Dieser heißt in diesem Fall ‘Car’. Wir sehen, dass es sich bei der class Anweisung ebenfalls um eine Block - Anweisung handelt, da nach der Bezeichnung der Klasse (Car) der Doppelpunkt folgt und die danach folgenden Methoden eingerückt sind.
Die einzelnen Methoden werden wie Funktionen definiert. D.h. die Definition erfolgt durch das Schlüsselwort def. Als Unterschied gibt wird jedoch ein zusätzlicher Parameter an erster Stelle angeführt, der zur Ausführungszeit der Methode mit der Referenz des aktuellen Objektes vom Laufzeitsystem belegt wird.

Das folgende Bild zeigt, wie Python den Speicher für die Objekte und die Klasse angelegt hat.

Sie können das Programm hier ausführen car.py.

Die Ausgabe wäre wie folgt:

VW/Passat 130.0 km/h VW/Jetta 130.0 km/h Dodge/Ram 100.0 km/h

Durch Aufrufen der Klasse (durch Angabe des Klassennamens) und Übergabe der Initialisierungsparameter wird eine neue Instanz angelegt. Die übergebenen Parameter werden verwendet, um die spezielle Methdode __init__ nach dem Anlegen der Instanz aufzurufen. D.h. zuerst wird das neue Objekt angelegt und danach wird diese spezielle Methode aufgerufen. Dazu wird auch dieser Methode die Referenz auf das gerade angelegte Objekt mitgegeben (als Parameter self).
D.h. in der Methode __init__ werden die Attribute cartype, kind und serNr für das gerade erzeugte Objekt angelegt. D.h. ab diesem Zeitpunkt besitzt das Objekt diese Attribute. Die Methode maxSpeed kann danach ebenfalls auf diese Attribute zugreifen.

Attribute gehören also zu einem Objekt und können in den Methoden abgefragt und verändert werden. Anders als in anderen Programmiersprachen ist es jedoch so, dass der Zugriff auf diese Attribute nicht nur ausschließlich in den Methoden erfolgen kann. Diese Attribute können prinzipiell auch von außerhalb gelesen und verändert werden, wie man in obigem Beispiel in der Zeile 21 (print(...)) sehen kann.

Labels: allgemeines, POS1-2, POS1-3, Python

# Eingestellt von Harald R. Haberstroh @ 14:52 0 Kommentare

Donnerstag, 18. Oktober 2012

Aufgabe Unit-Tests (POS1: 3BHIF)

Abgabename: 2012_3bhif_aufgabe3_ Name_Vorname.tgz

In einem Online-Shop wird unter anderem ein Warenkorb benötigt. Schreiben Sie Unit-Tests zu folgendem Interface (welches Sie natürlich auch implementieren müssen):

import java.util.Iterator;

/**

}

Denken Sie bei der Erstellung der Tests an Grenzfälle, Sonderfälle und erst dann an den "Normalfall".

Labels: Aufgabe, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 10:00 0 Kommentare

Sonntag, 30. September 2012

Abgaben (POS1: 2BHIF, 3BHIF)

Bis es ein zentrales Repository für Abgaben gibt, gilt folgende Form der Abgabe:

  1. Erzeugen Sie ein Mercurial-Repository (hg init).
  2. Arbeiten Sie an der Lösung der Aufgabe und nehmen Sie die neuen Dateien in Ihr Repository auf (hg add).
  3. Übergeben Sie einen fertigen Arbeitsschritt an das Repository (hg commit).
  4. Sind alle Teilaufgaben gelöst bzw. der Abgabetermin erreicht, packen Sie das Repository in ein Archiv mit dem Namen**jjjj_ N_bhif_aufgabe_N_ name_vorname.tgz**
  5. Kopieren Sie dieses Archiv in das Abgabeverzeichnis/home/teachers/hp/abgabe/_N_bhif/.

Dabei bedeuten:

jjjj

Die Jahreszahl des Schuljahresbeginns. Für das Schuljahr 2012/13 also 2012.

N

Bei der Klasse, der Jahrgang (also 2bhif, 3bhif) und bei der Aufgabe die Aufgabennummer (aufgabe1, aufgabe2...).

name_vorname

Ihr Name und Vorname in Kleinbuchstaben sowie ohne Umlaute, scharfes s (ß) und Akzente.

Beispiel:

2012_3bhif_aufgabe2_mayer_juergen.tgz

Dieses Archiv sollte in das Verzeichnis

/home/teachers/hp/abgabe/_3_bhif/

kopiert werden.

Bei jeder Aufgabe steht nun zur Erinnerung ganz oben der Abgabename. Zum Beispiel:
Abgabename: 2012_3bhif_aufgabe2_ name_vorname.tgz

Erstellen Sie auch für die bereits per Mail abgegebenen Aufgaben Repositories, packen Sie diese in ein entsprechendes Archiv und geben Sie es wie oben beschrieben ab!

Labels: allgemeines, Aufgabe, POS1-2, POS1-3

# Eingestellt von Harald R. Haberstroh @ 21:21 0 Kommentare

Dienstag, 25. September 2012

Aufgabe Regex (POS1: 3BHIF)

Abgabename: 2012_3bhif_aufgabe2_ Name_Vorname.tgz

ClassFinder

Erstellen Sie ein Projekt class_finder und erzeugen Sie ein Mercurial Repository dafür.

Schreiben Sie eine Java-Klasse MyClassFinder, welche folgendes Interface implementiert (Header wurde weggelassen):

package classfinder;

import java.io.FileNotFoundException; import java.io.IOException; import java.util.LinkedList;

public interface ClassFinder { /**

/**

Ihre Klasse darf im Prinzip einen beliebigen Namen haben, nur nicht classfinder.ClassFinder, denn das ist der Name des Interfaces, welches implementiert werden muss (in einem anderen Paket, darf die Klasse natürlich gleich heißen).

Die Idee der Methode findClassFiles(String pattern) ist es, das Aktuelle Verzeichnis und die Unterverzeichnisse nach Klassen (Java-Dateien) zu durchsuchen, die dem gegebenen Muster entsprechen.

Beispiele für Muster und das Ergebnis:

MyList

liefert folgende Dateien:

MyList.java myList.java ThatMyList.java MylistMaker.java

CF

liefert folgende Dateien:

CF.java ClassFinder.java CharacterFixer.java CharFinderFactory.java

Die Methode findMethodFiles(String pattern) liefert die Klassennamen (ohne .java), welche die gesuchten Methodendeklarationen enthalten. Eine Methode passt, wenn der Name einfach den String pattern (Groß-/Kleinschreibung ignorierend) enthält oder einfach nur die Buchstaben in der gegebenen Reihenfolge enthält. In diesem Fall muss der Methodenname mit dem ersten Buchstaben beginnen.

Beispiele für Muster und die passenden Methoden:

doThis

passt zu folgenden Methodennamen:

doThis dothis tryToDoThis doTaskHelp_i_ngs

ScM

passt zu folgenden Methodennamen:

scm doScm searchClassMembers setCornerMarker

Natürlich müssen aber die dazugehörigen Klassennamen geliefert werden, ggf. mit package (z.B. classfinder.MyClassFinder).

Testen

Schreiben Sie eine (JUnit-) Testklasse ClassFinderTest, welche die Methoden ausreichend testet.

Main

Schreiben Sie eine Hauptklasse Finder, welche ein passendes Konsoleninterface zu ClassFinder bietet:

hh@knuth:$ java Finder -c MyList MyList.java myList.java ThatMyList.java maker/MylistMaker.java hh@knuth:$ java Finder -m ScM MyClass helpers.Helper gui.Main gui.Frame hh@knuth:$ java Finder -h Finder, a java-tool for finding classes and methods. (c) 2012, Harald R. Haberstroh hh@knuth:$

Die Hervorhebung der passenden Zeichen ist optional. Die Hilfe sollte natürlich etwas ausführlicher sein und muss Ihren Namen enthalten.

Hinweise

Labels: Aufgabe, Informatik, Java, POS1-3

# Eingestellt von Harald R. Haberstroh @ 12:19 0 Kommentare

This page is powered by Blogger. Isn't yours?

Abonnieren Kommentare [Atom]