6.7 Übungen

Duke als Boxer

6.7.1 Referenzieren, Dereferenzieren und GC

Implementieren Sie die Klasse Person mit folgenden Eigenschaften:

  • Attribute für Vater und Mutter vom Typ Person
  • Statisches Attribut zum Zählen aller erzeugten Instanzen
  • Konstruktor
    • Eingabeparameter Anzahl der Vorfahrengenerationen
    • Erzeugen der Vorfahren durch Belegen der Attribute Vater, Mutter
    • Erhöhen Sie den Personenzähler
    • Drucken Sie einen Punkt pro tausend erzeugter Objekte
    • Tipp: Der Konstruktor ist rekursiv!

Hauptprogramm mit folgenden Eigenschaften:

  • Eingabe von n Generationen
  • Eingabe ob explizite GC erfolgen soll
  • Anlegen einer Person p1 mit n Generationen
  • Anstoßen einer Garbage Collection falls gewünscht
  • Anlegen einer neuen Person auf p1 mit n Generationen
Person mit Vorfahren

 

Testen des Programms mit den Optionen -Xms -Xmx -Xlog:gc

Beispiel:

java -Xms64m -Xmx256m -Xlog:gc block7.gc.Main

Dies bewirkt das Starten einer Javaanwendung mit

  • 64 Megabyte initialem Freispeicher (-Xms64m)
  • 256 Megabyte maximalem Freispeicher (-Xmx256m)
  • Protokollieren auftretender Garbagecollections (-Xlog:gc)

Allgemeine Überlegungen:

  • Wie kann man erzwingen das die erste Person und Ihre Vorfahren zum Löschen freigegeben werden?
  • Fügen die unten aufgeführte Kontrollmethode zum Auslesen der Speicherdaten an interessanten Stellen aus.

Tipp: Benutzen die folgende Beispielmethode zum Auslesen des Speicherverbrauchs.

Aufgaben

Variieren Sie den initialen, maximalen Speicher sowie die Anzahl der Generationen um

  • Implizite GCs zu provozieren, zu vermeiden
  • Eine OutOfMemory Ausnahme zu provozieren
  • Erhöhen Sie Ihren Speicherverbrauch bis Sie an die Grenzen Ihres Systems kommen. Vorsicht! Nähern Sie sich Ihren Systemgrenzen in kleinen Schritten. Ihr System kann für eine gewisse Zeit durch Überlastung unbenutzbar werden!

Ein Testprogramm

Anbei ein einfaches Testprogramm welches eine Person ohne Vorfahren erzeugt und dann in einer Schleife neue Personen mit immer mehr Vorfahren erzeugt.

Die Konstante mit den Generationen kann bis zu einem Wert von etwa 20 erhöht werden.

package s1.block6;
public class Test {
    /**
     * Zu erzeugende Generationen
     */
    public static int generationen = 3; // Initial testen
    //public static int generationen = 19; // mit -Xlog:gc
    //public static int generationen = 22; // mit -Xmx500m -Xlog:gc
    //public static int generationen = 23; // mit -Xms500m -Xmx1024m -Xlog:gc
    public static void main(String[] args) { 
        Person p;       
        systemStatus();
        for (int i=0; i<= generationen; i++) {
            System.out.println("*** Erzeuge " + i + " Generationen ***");
            // Der alte Personenbaum wird implizit dereferenziert
            p = new Person(i);
            // Verlängern der Laufzeit. Dies erlaubt eine bessere Beobachtung mit jonsole
            // Der alte Vorfahrenbaum wird durch die Zuweisung dereferenziert
            //p = new Person(i);
            //p = new Person(i);
            systemStatus();
            System.out.println("*** Ende. Erzeuge " + i + " Generationen ***");       
        }
    }
    public static void systemStatus(){
        Runtime r = Runtime.getRuntime();
        System.out.println("*** Systemstatus ***");
        System.out.println("* Prozessoren :       " + r.availableProcessors());
        System.out.println("* Freier Speicher:    " + r.freeMemory());
        System.out.println("* Maximaler Speicher: " + r.maxMemory());
        System.out.println("* Gesamter Speicher:  " + r.totalMemory());
        System.out.println("***  Ende Systemstatus ***");
    }
}

6.7.2 Tiefes Kopieren

Benutzen Sie den Quellcode der vorhergehenden Übung.

Schreiben Sie eine Klasse mir dem Namen Adresse und den folgenden Eigenschaften

  • öffentliche Attribute ort, plz, strasse, hausnummer
  • einen öffentlichen Konstruktor der alle Attribute erfasst
  • einen "Copy Constructor" für die Klasse

Erweitern Sie die Klasse Person wie folgt:

  • Attribut wohnort vom Typ Adresse
  • "Copy Constructor" für die Klasse

Wenden Sie den "Copy Constructor" im Hauptprogramm an.

Optional

Schreiben Sie einen "Copy Constructor" der maximal n Generationen kopiert.

6.7.3 Tiefes Vergleichen

Erweitern Sie die Klassen aus den vorgehenden Beispielen wie folgt:

Klasse Person

  • Fügen Sie einen Konstruktor hinzu der Name und alle vier Parameter für einen Geburtsort erfasst
  • Implementieren eine equals() Methode die den Vergleich basierend auf Namen und den Inhalten des Geburtsort ausführt

Klasse Adresse

  • Implementieren Sie eine  equals() Methode die auf alle Attribute der Klasse prüft

Hauptprogramm

  • Entwickeln Sie Testroutinen die die unterschiedlichen möglichen Fälle abprüfen

Tipp Die equals() Methode muss aus Typisierungsgründen ein Objekt vom Typ Object übernehmen. Mit dem unten aufgeführten Codestück kann man testen ob der EIngabeparameter vom gleichen Typ wie das aktuelle Objekt ist. Ist dies nicht der Fall so können die Objekte nicht gleich sein.

public boolean equals(Object obj) {
         ...
         if (this.getClass() == obj.getClass() )

6.7.4 "Walkthrough" Beispiel

Die hier gezeigte Übung wird interaktiv in der Vorlesung entwickelt. Die Arbeitsanweisungen sind im Quellcode enthalten.

Der Ausgangspunkt ist die Klasse Ware und die Klasse Lager die als Hauptprogramm dient:

KLasse Ware mit den erzeugten Instanzen

Ziel ist es eine Lösung zu entwickeln in der die Klasse Ware mit einem Lager verwendet werden kann:

Lager und Waren in UML

Klasse Ware

package s1.block6;
/**
 * Dies ist die Dokumentation der Klasse Ware. Ware dient zum Verwalten von Gütern
 * mit Preisen und Namen in einem Lager. 
 * @author  Stefan Schneider 
 * @version 1.1
 * @see     Lager
 */
public class Ware {
    /*
     * 7. Anlegen eine Copy Constructor
     * 7.1 Alle Werte des Objekts werden kopiert
     * 7.2 Es wird bei Bedarf eine neue Empfehlung angelegt
     */
    /**
     * Der aktuelle Mehrwertsteuersatz 2010.
     * Er liegt zur Zeit bei {@value}.
     * @since 1.0
     * @version 1.0
     */
    public static final double mws = 0.19;
    private double nettoPreis; //Deklaration
    public boolean halbeMws;
    private String name;
    public Ware empfehlung;
    /**
     * Konstruktor fuer die Klasse Ware
     * @param n der Name der Ware
     * @param np der Nettorpreis
     * @param hmws halber Mehrwertsteuersatz für Ware gueltig
     */
    public Ware(String n, double np, boolean hmws) {
        name = n;
        nettoPreis = np;
        halbeMws = hmws;
    }
    /**
     * Liefert den Namen einer Ware zurueck.
     * @return    Name der Ware
     */
    public String get_name() {
        return name;    }
    /**     * Setzen eines neuen Nettopreis
     * @param npr   der neue Nettopreis
     */
    public void set_nettoPreis(double npr) {
        nettoPreis = npr;
    }
    /**
     * Ausdrucken aller Werte auf der Konsole
     */
    public void drucken() { drucken(0); }
    /**
     * Ausdrucken aller Werte auf der Konsole mit vorgebener Einrueckung
     * für Empfehlungen
     * @param einruecken eingerueckte Stellen für Empfehlungen
     */    
    private void drucken(int einruecken) {
        String leerStellen = "";
        for (int i = 0; i < einruecken; i++) {
            leerStellen = leerStellen + " ";
        }
        System.out.println(leerStellen + "Name: " + name);
        System.out.println(leerStellen + "netto: " + nettoPreis);
        System.out.println(leerStellen + "Brutto: " + bruttoPreis());
        System.out.println(leerStellen + "Halbe Mws:" + halbeMws);
        if (empfehlung != null) { // Empfohlene Bücher werden eingerückt
            empfehlung.drucken(einruecken + 2);
        }
    }
    /**
     * Ausgabe des Nettopreis
     * @return der Nettopreis
     */
    public double nettoPreis() {
        return nettoPreis;    }
    /**
     * Ausgabe des Bruttopreis
     * @return der Bruttopreis
     */
    public double bruttoPreis() {
        double bp; //temporaere Variable; keine Klassenvariable
        if (halbeMws) {
            bp = Math.round(nettoPreis * (mws / 2 + 1) * 100) / 100;
        } else {
            bp = Math.round(nettoPreis * (mws + 1) * 100) / 100;
        }
        return bp;
    }
}

Klasse Lager 

package s1.block6;
/** * Die Klasse Lager verwaltet eine bestimmte Anzahl von Waren 
 * @author s@scalingbits.com
 */
public class Lager {
    /*     * Aufgaben
     * 1. Verwalten von n Waren in einem Feld
     * 1.1 Deklarieren eines privaten Feldes
     * 1.2 Zugriffsmethoden zum Setzen und Auslesen des Feldes
     * 2. Implementieren eines Konstruktors der das Lager
     *           für n Waren initialisiert
     * 3. Methode zum Ausräumen des Lagers
     * 4. Erzeugung eines Singletons zum Erzeugen genau eines Lagers
     * 5. Anlegen einer neuen Klasse MainLager
     * 5.1 Umkopieren der main() Methode aus der Klasse Lager in die Klasse
     *      MainLager.main()
     * 8. Testen des Copy Constructors
     * 8.1 Belegen Sie die ersten 500 Lagerpositionen mit Waren
     * 8.2 Klonen Sie die ersten 500 Lagerpositionen und belegen Sie die
     *     folgenden 500 Lagerpositionen mit Ihnen
     * 8.3 Löschen Sie Ihr Lager indem Sie alle Postionen mit null belegen
     * 8.4 Implementieren Sie eine Schleife die einige Minuten läuft
     *      und testen Sie den Speicherverbrauch mit jconsole oder
     */
     public static void main(String[] args) {
        Ware ware1 = new Ware("Zeitung",12.12,true);
        System.out.println("Ware1 ohne Empfehlung:");
        ware1.drucken();
        double p = ware1.nettoPreis();
        Ware ware2 = new Ware("Potter Bd1",31.12,false);
        Ware ersterBand = ware2;
        ware1.empfehlung= ware2;
        System.out.println("Ware1 mit Empfehlung:");
        ware1.drucken();
        // Erzeugen einer Ware mit 7 verketteten Empfehlungen
        Ware ware3;
        Ware hp1=ware2; 
        for (int i=2; i<= 7; i++) {
            ware3 = new Ware("Potter Bd" + i,31.25+i,false);
            ware2.empfehlung = ware3;
            ware2 = ware3;
        }
        System.out.println("Alle Harry Potter Baende drucken");
        hp1.drucken();
 }
}

Klasse MainLager

package s1.block6;
/**
 * * Eine Hilfsklasse zur Implementierung eines Hauptprogramms
 *
 * @author sschneid
 * @version 1.0
 */
public class MainLager {
    /*
     * 6. Testen der Klasse Main 
     * 6.1 Aufruf des Singleton der Klasse Lager 
     * 6.2 Einfügen zweier Waren 
     * 6.3 Drucken zweier Waren
     */
    public static void main(String[] args) {
        Ware ware1 = new Ware("Zeitung", 12.12, true);
        ware1.drucken();
        double p = ware1.nettoPreis();
        Ware ware2 = new Ware("Potter Band 1", 31.12, false);
        Ware ersterBand = ware2;
        Ware ware3;
        for (int i = 2; i <= 7; i++) {
            ware3 = new Ware("Potter Band" + i, 31.12, false);
            ware2.empfehlung = ware3;
            ware2 = ware3;
        }
    }
}