Jaff : Java für Förster 01.12.03 J. Nagel Seite 1 von 48 Skript Java für Förster Technologie der Informationsverarbeitung im Schwerpunkt Waldökosystemanalyse u. Informationsverarbeitung © 2001-2003 Prof. Dr. Jürgen Nagel http://www.gwdg.de/~jnagel Jaff : Java für Förster 01.12.03 J. Nagel Seite 2 von 48 EINLEITUNG ............................................................................................................................................................. 3 MOTIVATION............................................................................................................................................................. 3 ORGANISATORISCHES ............................................................................................................................................... 4 GRUNDLAGEN.......................................................................................................................................................... 5 EINFÜHRUNG IN DIE PROGRAMMIERSPRACHE ........................................................................................................... 5 DATENORGANISATION .............................................................................................................................................. 6 LITERATUR UND INTERNET ....................................................................................................................................... 6 VORBEREITUNG ........................................................................................................................................................ 7 DAS ERSTE PROGRAMM ............................................................................................................................................ 8 DIE GRUNDRECHENARTEN ...................................................................................................................................... 10 DATENTYPEN .......................................................................................................................................................... 11 KONDITIONALE ANWEISUNGEN .............................................................................................................................. 13 SCHLEIFEN .............................................................................................................................................................. 14 ARRAYS .................................................................................................................................................................. 17 KLASSEN.................................................................................................................................................................. 18 ZWECK UND AUFBAU .............................................................................................................................................. 18 EINFACHES KLASSENBEISPIEL ................................................................................................................................ 20 HÜLLKLASSEN UND UMWANDELN VON DATENTYPEN ............................................................................................ 25 KLASSE MATH ........................................................................................................................................................ 26 KLASSE DECIMALFORMAT...................................................................................................................................... 27 LESEN UND SCHREIBEN AUS DATEIEN ......................................................................................................... 29 JAVA API.................................................................................................................................................................. 36 GRAFIK .................................................................................................................................................................... 36 DOKUMENTATION MIT JAVADOC ............................................................................................................................. 44 WEITERGABE .......................................................................................................................................................... 44 INDEX........................................................................................................................................................................ 48 Jaff : Java für Förster 01.12.03 J. Nagel Seite 3 von 48 Einleitung Motivation Der Kurs nennt sich Java für Förster (JAFF) und ist als Einführung in die Programmierung gedacht. Warum könnte überhaupt ein Förster um alles in der Welt ein Interesse daran haben, programmieren zu lernen? Reicht es nicht aus, wenn er draußen im Wald ist? Sicher ist, daß sich diese Frage nicht eindeutig beantworten läßt. Aber in den letzten Jahren hat sich das Berufsbild erheblich verändert. Vorbei ist die Idylle. Rationalisierung und Produktivitätsfortschritt sind in einer nachhaltigen multifunktionalen Forstwirtschaft gefordert, die zunehmend einen Ausgleich zwischen den Interessen verschiedender Gruppen und Verbände anstreben muß. Kein Wunder, daß moderne Informationstechnologien auch die abgelegensten Forsthäuser erreicht haben und der Computer zum alltäglichen Werkzeug für die Betriebsführung, die Planung und die Präsentation geworden ist. Darüber hinaus gibt es heute eine wachsende Zahl von "Förstern", die als Freiberufliche ihren Lebensunterhalt mit z.T. wechselnden Aufgaben verdienen. In den meisten Fällen sind dabei gute Kenntnisse im Umgang mit Textverarbeitung, Tabellenkalkulation, Datenbanken und Präsentationsprogrammen unumgänglich. Häufig kommt es vor, daß der Datenfluß vom einen zum anderen Standardprogramm am Format hapert oder kleine Details mit diesen Programmen nicht oder nur aufwendig ausgewertet werden können. Genau für diese Fälle soll der Kurs eine Hilfe zur Selbsthilfe sein. Gleichzeitig wird er aber auch ein besseres Verständnis in den Umgang mit Computerprogrammen vermittelt. Es gibt viele Sprachen mit denen man Computerprogramme schreiben kann. Die Elemente dieser Sprachen sind weitgehend ähnlich und daher ist es für die meisten Programmierer auch nicht zu schwierig, von einer auf die andere Programmiersprache umzulernen. In diesem Kurs soll das Programmieren mit der Sprache Java erlernt werden. Es handelt sich dabei um eine moderne und objektorientierte Sprache, die sich auch gut für Internetanwendungen einsetzen läßt. Der größte Vorteil der Sprache Java ist aber der, daß die geschriebenen Programme auf verschiedenen Betriebssystemen (DOS, Windows, LINUX, etc.) eingesetzt werden können. Es gilt daher der Grundsatz „write once and use multiple“. Für die Programmierung mit Java gibt es zwar eine Reihe hilfreicher Entwicklungsumgebungen wie den JBuilder (Borland) und Forte (Sun). Aber die Grundlagen lassen sich besser ohne eine solche Entwicklungsumgebung erklären. Man benötigt lediglich das Java Development Kit der Firma Sun, welches kostenfrei aus dem Internet zugänglich ist. Wenn man dann die Grundlagen von Java beherrscht und auf die zahlreichen vorhandenen Funktionen und Möglichkeiten der Sprache bequemer zugreifen möchte, kann man leicht und mit dem nötigen Verständnis auf eine solche Entwicklungsumgebung umsteigen. Der Kurs ist auf Studenten des Forststudiums ausgerichtet und nennt sich daher Java für Förster. In den Beispielen werden forstliche Probleme bearbeitet. Über den gesamten Kurs soll ein einfaches Wachstumsmodell mit Oberfläche und Grafik entstehen, in dem alle wichtigen und grundlegenden Bereiche der Programmierung mit Java verdeutlicht werden. Dieses einfache Wachstumsmodell kann als Grundlage für weitere Anwendungen verwendet werden. Der Kurs Jaff : Java für Förster 01.12.03 J. Nagel Seite 4 von 48 ist aber auch für Studenten anderer Fachbereiche geeignet, die sich Programmierkenntnisse für kleine Problemlösungen aneignen möchten. Programmieren kann man nur durch selbstständiges programmieren lernen. Daher sollten Sie die Kapitel sorgfältig durcharbeiten und Sie sollten die Übungsaufgaben lösen. Ich empfehle Ihnen auch den Code abzutippen und zu verstehen. Mit „cut and paste“ (ausschneiden und einfügen) geht es schneller, aber häufig leidet darunter das Verständis. Dazu ist eine gewisse Portion Hartnäckigkeit gefragt. Aber aus Fehlern kann man nur lernen. Es ist nicht der Computer der Sie ärgern will, es liegt fast immer an Ihnen, wenn Ihr Programm nicht das ausführt, was Sie gerne möchten. Beweisen Sie sich, daß Sie es können! Hat man erst mal einige Programme selbst erstellt, kann man auf diese Grundgerüste bei neuen Aufgaben immer wieder zurückgreifen. In dem Sinne ist auch dieser Kurs aufgebaut. In einigen kleinen Programmen werden Ihnen zunächst die Grundlagen vermittelt. Daran schließen sich einige größere Projekte an, die auf diesen Grundlagen aufbauen. Die größeren Projekte wiederum können Ihnen als Beispiel dienen, wenn Sie eigene umfangreiche Projekte realisieren wollen. Organisatorisches Laden Sie sich zunächst die Java 2 Platform, Standard Edition (J2SE)1 und die dazugehörige Dokumentation für Ihr Betriebsystem (Windows, Mac, Linux, etc..) aus dem Internet und installieren Sie das Programm und die Dokumentation (http://java.sun.com/j2se/). Legen Sie sich ein Unterverzeichnis JAFF an. In dieses Verzeichnis wollen wir die Beispielprogramme schreiben. Sie finden die Beispielprogramme im Ordner jaff\example. Versuchen Sie jedoch immer zuerst die Programme selber zu schreiben. Entgegen der sonstigen Geflogenheit die Klassennamen und die dazugehörigen Dateinamen von Java mit einem großen Buchstaben beginnen zu lassen, habe ich mich entschieden, alle Dateinamen lieber nur klein zu schreiben. Dies ist zwar nicht ganz so übersichtlich, hat jedoch den Vorteil, daß es beim Kopieren und Entpacken der Dateien nicht zu einer systembedingten Änderung der Groß- und Kleinschreibung kommt und damit die Dateien leichter von Windows auch auf das Betriebssystem Linux übertragen werden können, ohne daß man die Benamung hinterher wieder ändern muß. Im weiteren Text finden sie einige Begriffe, die fett geschrieben sind. Dies sind wichtige Begriffe für das weitere Verständis. Wenn Sie auf grünen, fetten Text in Times New Roman 10 stoßen, so handelt es sich um Programmcode. Zu jedem Programmbeispiel gehört meist ein eigenes Java Programm. Die Programme sind z.B. mit p1 usw. benannt. Benennen Sie Ihre Programm möglichst genauso. Programmausgaben sind in fetten Text in Times New Roman 10. Rot und fett geschriebener Text gibt Ihnen nur wichtige Tips. Dunkelblau in Courier 10 sind Daten. Die Projekte werden in eigenen Verzeichnissen gespeichert. Falls Sie Fehler in diesem Text entdecken, wäre es nett, wenn Sie diese mitteilen würden. Falls 1 Die Java 2 Platform, Standard Edition (J2SE), die dazugehörige Dokumentation und aller Beispielprogramme finden Sie auch auf der CD-ROM Forest Tools ab der Version SS02. Für mehr Informationen und zum Bestellen der CD sehen Sie bitte auf dem Internet unter http://www.gwdg.de/~jnagel/cdft.html nach. Jaff : Java für Förster 01.12.03 J. Nagel Seite 5 von 48 Sie Verbesserungsvorschläge haben, so sind diese auch willkommen. Schicken Sie eine E-Mail an: [email protected] Grundlagen Einführung in die Programmiersprache Computer (ursp. von lat. computare = berechnen) sind universell arbeitende Geräte zur Verarbeitung von Informationen. Einen Computer kann man zur Erfüllung verschiedener Aufgaben verwenden, z.B. zum Rechnen, zur Textverarbeitung, zur Steuerung von Maschinnen und zum Spielen. Dazu benötigt der Computer nur das richtige Programm zur Steuerung der Abläufe. Ein Algorithmus ist ein allgemeines Verfahren zur Lösung einer Folge gleichartiger Probleme. Diese besteht aus einer Folge von Anweisungen, die präzise formuliert sind. Ein Algorithmus kann also auch von Menschen oder Maschinen ausgeführt werden, die die Anweisungen genau verstehen. Einem Computer müssen die Anweisungen in geeigneter Form zur Verfügung gestellt werden. Dazu gibt es die Programmiersprachen. Ein Computerprogramm ist die Formulierung eines Algorithmus entsprechend den Regeln einer Programmiersprache. Die Syntax ist das Regelwerk einer Programmiersprache und definiert, welche Texte in der jeweiligen Programmiersprache gelten. Die Semantik definiert die Bedeutung der einzelnen Sprachelemente. Wer die Syntax und die Symantik kennt, kann Computerprogramme lesen und verstehen. Die Programmiersprache dient also der Verständigung zwischen Menschen und zwischen Mensch und Maschine, in dem ein Algorithmus formalisiert beschrieben wird. Die eigentliche Sprache, die ein Computer versteht, ist die Maschinensprache. Man kann Rechner direkt in Maschinensprache programmieren, indem man einen Assembler verwendet. Dies ist jedoch unübersichtlich und nicht produktiv. Die Maschinensprache ist darüber hinaus vom Prozessor des Computers abhängig. Man kann nun die Maschinensprache auf zwei Wege umgehen. Erstens übersetzen Compiler eine verständlichere Sprache in Maschinenanweisungen und zweitens können Interpreter die Anweisungen einer Sprache lesen und dann zu jeder Anweisung eine Anzahl von Maschinenbefehlen ausführen. Die bekanntesten höheren Programmiersprachen sind C, C++, Pascal (Delphi), (Visual) Basic und Fortran. Sie verfügen über Compiler. Als Interpreter Sprachen lassen etwa Access und Excel Skripte verstehen. Java ist eine Sprache die zwischen Compilier und Interpreter einzuordnen ist. Das compilierte JavaProgramm ist vom Prozessor unabhängig und die Interpretation des Byte-Code kann wesentlich schneller erfolgen als die direkte Interpretation des Programmtextes. Java hat in den letzten Jahren als Sprache an Bedeutung gewonnen, weil sie auch vom Betriebssystem des Computers (DOS, Windows, Unix) unabhängig ist. In diesem Skript wird nun an einfachen Beispielen die Programmierung mit Java verdeutlicht. Die Beispiele sind für das Betriebssystem Windows meist im DOS Fenster erklärt. Sie können aber auch leicht unter Unix oder Linux nachvollzogen werden. In den Anfangsbeispielen wird bewußt auf eine Java Entwicklungsumgebung verzichtet, damit die Grundlagen von Java klarer werden. Jaff : Java für Förster 01.12.03 J. Nagel Seite 6 von 48 Datenorganisation Die Daten auf einer Festplatte sind in Dateien (Files) organisiert. Meist ist eine Festplatte hierarchisch in Verzeichnisse untergliedert. An der Spitze steht unter DOS das Wurzelverzeichnis (root) eines Laufwerks (drive). Jedes Laufwerk hat einen eigenen Namen, den Laufwerksbuchstaben. Die 1. Festplatte wird meist mit C: angesprochen. Verzeichnisse werden durch Schrägstriche \ abgegrenzt. Unter Unix wird der entgegengesetzte Schrägstrich verwendet (/). Der Dateiname besteht unter DOS aus 8 Zeichen und einer Extension, die vom Dateinamen durch einen Punkt abgesetzt ist. C:\Unterverzeichnis\Unterunterverzeichnis\Datei.txt Im DOS - Eingabefenster kann man mit den Befehlen: DOS Befehl cd .. cd Unterverzeichnisname mkdir Neuesverzeichnis rmdir Verzeichnis dir Erklärung in eine höhere Verzeichnisebene gelangen ein Unterverzeichnis aufrufen ein neues Unterverzeichnis anlegen ein Unterverzeichnis löschen, wenn es leer ist Anzeigen aller Dateien und Unterverzeichnisse des Verzeichnises Möchte man unter DOS, daß das Betriebssytem ein spezielles Verzeichnis nach Programmen durchsucht, wenn man in einem anderen Verzeichnis gerade arbeitet, so kann man dies mit dem path Befehl erreichen. Man erweitert den path-Befehl für die Java-Programme mit der folgenden Zeile: path %PATH%;C:\jdk1.3.1_01\bin Dies gilt natürlich nur, wenn Java auch in diesem Verzeichnis installiert ist. Darüber hinaus sollte die Classpath Variable noch entsprechend eingestellt sein. Der Ausdruck .; gibt an, daß zuerst das aktuelle Verzeichnis durchsucht werden soll. SET CLASSPATH=.;c:\jdk1.3.0_02\lib Beide Einstellungen können Sie bei Windows 95 bis ME dauerhaft festlegen, in dem Sie sie in die Datei autoexec.bat schreiben. Literatur und Internet Dieses Skript erhebt nicht den Anspruch ein Lehrbuch zu ersetzen. In ihm werden lediglich einige Grundlagen angesprochen und an Beispielen erklärt. Es soll insbesondere für den Typ von Student eine Hilfe sein, der eine Programmiersprache nach dem Prinzip „Learning by doing“ erlernen möchte. In dem Skript werden nur die grundlegenden Elemente der Programmierung erklärt, welche man zur Lösung spezieller forstlicher Algorithmen benötigt. Die Programmierung von Benutzeroberflächen wird in diesem Skript nur an einigen wenigen Beispielen ansatzweise erläutert, eine ausführliche Erklärung würde den Rahmen dieses Buches sprengen. Das gilt auch für die Programmierung von Datenbanken. Jaff : Java für Förster 01.12.03 J. Nagel Seite 7 von 48 Wer jedoch die Grundlagen beherrscht und versteht, dem sollte es ein Leichtes sein, sich in die Programmierung von Datenbanken und Benutzeroberflächen einzuarbeiten. Dabei sollte man nicht den Ehrgeiz haben, und versuchen, alles von Grund auf alleine programmieren zu wollen. Im Internet und im Buchhandel werden Sie zahlreiche Beiträge und Lehrbücher zur Programmierung mit Java finden. In diesen findet man Beispiele und Programmteile, die man für die Lösung der eigenen Probleme nutzen kann. Oft muss man nur kleine Veränderungen durchführen. Für den Anfänger würde ich das Buch von Abts (2000) empfehlen. Das Buch von Solymosi und Schmiedecke vertieft den Umgang mit Objekten, dazu sollte der Leser aber schon gut mit Java vertraut sein. • • Abts, D. (2000): Grundkurs Java. Vieweg Verlag, Braunschweig/Wiesbaden, 334S. Solymosi, A.; Schmiedecke, I. (2000) :Programmieren mit Java. Vieweg Verlag, Braunschweig/Wiesbaden, 356S. Im Internet ist darüber hinaus eine große Anzahl von Online- Tutorien zu finden. In diesen findet man z.T. gute Erklärungen und auch hilfreiche Beispiele. Sehr zu empfehlen ist der Java Kurs von Grothmann der Universität Eichstätt. • http://mathsrv.ku-eichstaett.de/MGF/homes/grothmann/java/kurs • http://java.rrzn.uni-hannover.de/tkji/javakurs/kursdemos/index.html • http://www.galileocomputing.de/katalog/openbook?GalileoSession=59814873A1BgEhil.MQ (hier kann man sich kostenlos ein ganzes Java-Buch herunterladen, wenn man sich keins kaufen will) • oder anschauen: http://www.galileocomputing.de/openbook/javainsel3/ • Wichtige Hinweise und Hilfestellungen zum Thema Java findet man auf den Seiten: • • • http://developer.java.sun.com/developer/support/ http://java.seite.net/ http://www.javaworld.com/ Vorbereitung Bevor Sie jedoch anfangen, sollten Sie überlegen, wo Sie auf der Festplatte, dem permanenten Speicher Ihres Computers, Ihre Java-Programm ablegen wollen, so dass Sie sie auch vielleicht nach langer Zeit noch wieder finden können. Zu diesem Zweck kann der Speicher in Verzeichnisse und Unterverzeichnisse eingeteilt werden. Es ist sinnvoll, wenn Sie Ihre Daten von den Programmen trennen, denn wenn Sie z.B. eine neue Version eines Textverarbeitungsprogramms wie Word auf Ihren Computer bringen, können Sie die alte Jaff : Java für Förster 01.12.03 J. Nagel Seite 8 von 48 Version vorher löschen, ohne dass Ihrer Texte aus Versehen verloren gehen, wenn die Texte in einem separaten Verzeichnis gespeichert sind. Darüber hinaus können Sie auch eine Sicherheitskopie Ihrer Texte leichter anfertigen, indem Sie einfach das entsprechende Verzeichnis kopieren. Daher sollten Sie auch Ihre Java Übungsprogramme in ein eigenes Verzeichnis stellen. Erstellen Sie ein Unterverzeichnis JAFF (Java für Förster) in DOS oder Windows. Dieses Verzeichnis wird für die nächsten Übungen Ihr Java Arbeitsverzeichnis. Das erste Programm Programm p1.java: Mein erstes Programm Aufgabe: Wir wollen ein Programm schreiben, welches auf den Bildschirm die Zeile „ auch Förster lernen programmieren“ schreibt. Algorithmus: Er besteht in diesem Fall für uns aus einem einzigen Befehl, nämlich schreibe die Zeile „auch Förster lernen programmieren“. Programmierung: Schreiben Sie die folgenden Zeilen des Programms p1.java mit einem Texteditor in eine Datei und speichern Sie den Text als ASCII-Datei mit dem Namen p1.java ab. Dafür kann der Windows Benutzer z.B. das Programm Notepad verwenden. Es ist auch möglich z.B. WinWord dafür zu verwenden, bei diesem Programm müssen Sie jedoch darauf achten, dass Sie den Text als unformattiert abspeichern. Sonst enthält die Datei Steuerungszeichen mit denen der Java Compiler nichts anfangen kann. /* JAFF = Java fuer Foerster Programm 1 Mehrzeiliger Kommentar */ public class p1 { public static void main (String args[]) { System.out.println("auch Foerster lernen programmieren"); } } Speichern Sie den Text in einer Datei unter dem Namen p1.java und öffnen Sie ein DOSFenster. Achten Sie unbedingt auf die Groß- und Kleinschreibung. Dos und Windows sind da zwar nicht immer so wählerisch, aber Unix und Linux sind sehr empfindlich. Mancher Fehler kommt einfach daher, daß p1 nicht gleich P1 ist. Im DOS Fenster wählen Sie zuerst Ihr Verzeichnis JAFF (cd .. und cd jaff). Prüfen Sie mit dem Befehl DIR, ob wirklich eine Datei p1.java existiert und auch p1.java heißt. Nach dem dies erfolgreich geschehen ist, müssen Sie den Inhalt der Datei für den Java Interpreter übersetzen. Dazu rufen Sie den Java-Compiler auf. Das Java Compiler Programm heißt javac Dazu geben Sie den Befehl ein: Jaff : Java für Förster 01.12.03 J. Nagel Seite 9 von 48 C:\jaff>javac p1.java Lassen Sie sich nun mit dem Befehl Dir alle Dateien des Verzeichnisses jaff anzeigen. Sie können hoffentlich feststellen, daß Sie eine 2. Datei mit dem Namen p1.class erzeugt haben. Diese Datei enthält den Bytecode für den maschinenunabhängigen Bytecode-Interpreter von Java. Das Programm p1 können Sie nun beliebig oft ausführen, indem Sie die Datei p1.class mit dem Befehl aufrufen: C:\jaff>java p1 Es sollte auf dem Schirm die Zeile: auch Förster lernen programmieren erscheinen. Es mag sein, daß das ö ein wenig anders aussieht, aber die Feinheiten unterschiedlicher Ländereinstellungen und Code-Tabellen von Windows und DOS werden wir später besprechen. Die Datei p1.java können Sie theoretisch löschen. Zum Ausführen des Programms benötigen Sie nur die *.class Dateien. Die Datei p1.java möchten Sie aber dennoch nicht löschen, denn für den Fall, dass Sie später einmal das Programm verändern wollen, müssen Sie auf die Datei p1.java zurückgreifen können. Sehen wir uns das kleine Programm etwas näher an und besprechen erst mal nur einige Details. Im Laufe des Kurses wird der Aufbau von Klassen noch genauer besprochen. Die geschweiften Klammern markieren den Anfang und das Ende eines Blocks. In diesem Fall markiert der Block den Beginn und das Ende der Klasse mit dem Namen p1. public class p1 { } Es ist wichtig, dass der Klassenname (hier p1) und der Dateiname p1.java identisch auch in Bezug auf die Groß- und Kleinschreibung sind. Jedes Java Programm besteht aus einer oder mehreren Klassen. Die Hauptklasse muss eine Methode namens main haben. Sie muß public sein, d.h. sie kann auch von anderen Klassen genutzt werden. Die geschweiften Klammern markieren wieder Anfang und Ende, diesmal von der Methode main. public static void main (String args[]) { } Durch das Hinzufügen der Methode main wird aus der Klasse ein Hauptprogramm. Eine Methode ist ein in sich abgeschlossener Programmteil, der verschiedene Anweisungen enthalten kann. Die Methode main muß public und static deklariert werden. Eine mit public deklarierte Methode ist auch anderen Klassen zugänglich. Statische (static) Programmteile werden während der gesamten Laufzeit geladen, während dynamische nur bei Bedarf geladen werden. Die Methode main gibt kein Ergebnis zurück, daher void. Es kann, muß aber keine Zeichenketten über die Variable args übernehmen. Aus diesem Grunde ignorieren wir vorerst String args[]. Nehmen Sie bitte an dieser Stelle die kurze Erklärung der Methode main als gegeben hin, und konzentrieren Sie sich in den weiteren Beispielen zunächst auf den Text der zwischen die beiden geschweiften Klammern der Methode main geschrieben wird. Im Skript wird noch ausführlich auf den Sinn und Zweck von Methoden eingegangen. System.out.println("auch Foerster lernen programmieren"); Jaff : Java für Förster 01.12.03 J. Nagel Seite 10 von 48 Diese Zeile ruft die Methode println der Klasse System.out auf. Die Klasse System.out wird neben vielen anderen mit Java mitgeliefert und erlaubt einem, eine einfache Bildschirmausgabe zu machen. Der Methode println() kann in der Klammer als Parameter ein String übergebenen werden. Ein String ist eine Zeichenkette wie "auch Förster lernen programmieren". Sie werden in Hochkomma ("") gesetzt. Println() schreibt diese Zeichenkette auf den Bildschirm. Eine Kommandozeile wird in Java immer mit einem Semikolon (;) und nicht vom Zeilenende begrenzt. Eine Kommandozeile kann daher auch auf mehrere Zeilen aufgeteilt werden. Ein Zeilenkommentar kann durch 2 Schrägstriche // und ein mehrzeiliger Kommentar durch /* und */ abgegrenzt werden. Kommentare sollten grundsätzlich in Programme geschrieben werden. Sie helfen dem besseren Verständnis eines Programmes. Man kann auch einen Dokumentationskommtentar verwenden, der den Kommentar für das Programm Javadoc bereitstellt. In diesem Fall steht der Kommentar zwischen /** und */. Der Dokumentationskommentar muß direkt vor der Klasse, Variablen oder Methode stehen, für die er gilt. Aufgaben: 1) Schreiben Sie selbstständig ein eigenes Programm, welches Ihren Namen ausgibt. 2) Machen Sie bewußt einige Fehler und beachten Sie die Meldungen des Compilers. Die Grundrechenarten Mit einem weiteren Programm wollen wir uns die Grundrechenarten verdeutlichen. Programm p2.java: Einfache Rechenoperationen Aufgabe: Das Programm soll eine Meldung „Einfache Rechenoperationen“ ausschreiben. Es soll dann auf den folgenden Zeilen 2+2, 2*5, 11 : 4 und (2+2)*5 berechnet werden. Algorithmus: Wie im Programm p1.java soll das Programm zuerst eine Textausgabe durchführen. Danach soll es jeweils in einer Schreibanweisung den Text und die Lösungen für die genannten Rechnenaufgaben auschreiben. Programmierung: Schreiben Sie das Programm p2.java in eine separate Datei mit einem Texteditor. // JAFF = Einfache Rechenoperationen public class p2 { public static void main (String args[]) { System.out.println("Einfache Rechenoperationen"); System.out.println("2+2= "+(2+2)); System.out.println("3*5= "+(3*5)); System.out.println("11/4="+(11/4)); System.out.println("11.0/4="+(11.0/4)); System.out.println("11.0/4.0="+(11.0/4.0)); System.out.println("(2+2)*5= "+((2+2)*5)); } } In diesem Programm haben wir im Vergleich zu p1.java einige zusätzliche Kommandozeilen eingefügt. Sie demonstrieren die Grundrechenarten. Als arithmetische Operatoren gelten in den Anweisungen folgende Zeichen: Jaff : Java für Förster 01.12.03 + * / () J. Nagel Seite 11 von 48 Addition Substraktion Multiplikation Division Klammern In Java geht Punkt- vor Strichrechnung und die Klammer entsprechend. Lassen Sie das Programm compilieren und starten Sie das Programm. Vielleicht überrascht das Ergebnis von 11/4 gleich 2. Dieses Ergebnis ist nicht falsch, da wir mit ganzen Zahlen (Integer) rechnen. Wird die Division mit zwei Integerzahlen durchgeführt, werden die Nachkommastellen einfach vernachlässigt. Ist eine der beiden Zahlen ein relle Zahl, dieser Typ heißt in Java (double), erhält man die „genauere“ Ausgabe. Dies ist eine Falle, der man sich als Programmierer bewußt sein muß. Der Text, der in der Methode System.out.println() ausgegeben wird, kann z.b. mit dem Ergebnis einer Rechenoperation verkettet werden. Die Zeichenkette, die ausgegeben werden soll, steht in Hochkommtar. Die Rechenoperation wird in Klammern gesetzt und mit dem Text verkettet. Die Umwandlung der Integer bzw. double in eine Zeichenkette wird vom Programm automatisch durchgeführt. Aufgaben: 1) Schreiben Sie ein eigenes Programm und berechnen Sie folgendes: a) 5+6+7; b) (5-2)*17, c) 15-6*12 Datentypen Zur Speicherung von String (Zeichenketten), ganzen (int) und rellen Zahlen (double) benötigen die Programme unterschiedlich viel Speicherbedarf. Den Typ einer Variable kann man in fast allen Programmiersprachen an seine Bedürfnisse anpassen. Die wichtigsten Variablentypen sind: Datentyp short int float double byte char boolean Erklärung Ganze Zahl –215 .. 215 Ganze Zahl –231 .. 231 Gleitkomma Zahl ca,. 6-stellige Mantisse u. 2 stelliger Exponent Gleitkomma Zahl ca,. 16-stellige Mantisse u. 3 stelliger Exponent 0..255 Zwei byte Zeichen in Unicode Wahr (true) oder falsch (false) Die Datentypen werden in dem nächsten Programm demonstriert. Jaff : Java für Förster 01.12.03 J. Nagel Seite 12 von 48 Programm p3.java: Datentypen Aufgabe: Das Programm soll eine Meldung „Einfache Rechenoperationen“ ausschreiben. Es soll dann auf den folgenden Zeilen 2+2, 2*5, 11 : 4 und (2+2)*5 berechnet werden. Diesmal sollen allerdings Text und die Rechenoperationen nicht direkt im println eingegeben und berechnet werden, sondern zuvor in Variablen gespeichert werden. Algorithmus: Der Text und die Zahlen werden zunächst in Variablen gespeichert. Dafür soll jeweils der entsprechende Datentyp verwendet werden. Dann erfolgt die Ausgabe wie in p2.java Zeile für Zeile. Programmierung: Schreiben Sie das Programm p3.java in eine separate Datei mit einem Texteditor. Lassen Sie die Kommentare weg. Beachten Sie bitte die Kommentare. Einfache Kommentare beginnen mit einem // und gelten zum Zeilenende. Alle Variablen, die man in einem Programm benutzt, müssen in Java vorher erklärt bzw. erzeugt werden. public class p3 { public static void main (String args[]) { int n; // Erzeugung einer Integervariable namens n n=2; // Zuweisung des Wertes 2 zu n int m=3; // Erklärung und Zuweisung auf einer Zeile int k,l; // Erzeugung der zwei Integervariablen k und l k= 3; l=5; // Zwei Zuweisungen double x; // Erklärung einer double Variable namens x double y=11.0; // Zuweisung des Wertes 11.0 String s="Einfache Rechen"; // Erklärung und Zuweisung einer Stringvariable s // Ausschreiben der Variable s und zusätzliche Verkettung mit einem String System.out.println(s+"operationen"); // Ausschreiben von m+n System.out.println("2+2= "+(n+n)); System.out.println("3*5= "+(m*l)); // Berechnung von y/4 und Zuweisung nach x x = y/4; System.out.println("11/4="+x); System.out.println("(2+2)*5= "+((n+n)*l)); System.out.println("exp(2)= "+(Math.exp(2))); } } Die Variablen werden vor der Verwendung in dem Unterprogramm durch den Datentyp gefolgt vom Variablennamen deklariert. Mehrere Variablen eines Typs kann man durch die Trennung mit einem Komma in einer Kommandozeile definieren. Es lassen sich den Variablen auch sofort Werte zuweisen. In dem Programm finden sich auch einfache Kommandozeilen, in denen nur gerechnet wird. Die Methode exp der Klasse Math berechnet den Exponenten. Die Klasse Math wird mit Java geliefert und enthält zahlreiche nützliche mathematische Funktionen (s. Kap. Klassen). Aufgabe: Berechnen Sie das Volumen [m³] für eine Eiche mit einem BHD von 30 cm und einer Höhe von 20 m. Benutzen Sie dazu die Formzahlfunktion von Bergel (Der Durchmesser wird in der Formel in der Maßeinheit cm und die Höhe in m eingesetzt): Jaff : Java für Förster 01.12.03 f = 0.4786 − J. Nagel Seite 13 von 48 1.0111 2.104 203.12 + − d h d ⋅ h2 Konditionale Anweisungen In der Programmierung sind konditionale Anweisungen ein wichtiges Element zur Verzweigung von Programmabläufen. Grundlegend ist die IF (wenn) dann ELSE (sonst) Anweisung. Man kann auch nur die IF Anweisung (ohne ELSE) verwenden. In diesem Fall wird die folgende Kommandozeile ausgeführt, wenn die Bedingung zutrifft. Verwendet man auch die ELSE Anweisung, so wird entweder die nächste oder die auf ELSE folgende Kommandozeile ausgeführt. Die Ausführung mehrer Anweisungen, wenn die Bedingung wahr ist, kann man erreichen, indem man einen Block {} (geschweifte Klammern) setzt. IF Anweisungen lassen sich auch verschachteln. Einfache Vergleichsoperatoren sind: == != > < >= <= && || gleich ungleich größer kleiner größer gleich kleiner gleich und oder Programm p4.java: if (- else) Abfrage Aufgabe: Schreibe ein Programm welches eine Zufallszahl erzeugt, diese auf den Bildschirm anzeigt und entscheidet, ob die Zufallszahl größer gleich oder kleiner ein Halb ist. Algorithmus: Erzeugen einer Variable zur Speicherung der Zufallszahl. Ziehen der Zufallszahl. Konditionale Abfrage ob diese >= 0.5 ist oder nicht. Dabei die Entscheidung ausgeben. Eine Zufallszahl zwischen 0 und 1.0 erzeugen Sie mit der Methode Math.random(); Programmierung: Schreiben Sie das Programm p4.java in eine separate Datei mit einem Texteditor. Lassen Sie die Kommentare weg. Beachten Sie bitte die Kommentare. public class p4 { public static void main (String args[]) { double x; x=Math.random(); //erzeuge eine Zufallszahl zwischen 0 und 1 System.out.println("X ="+x); // konditionale Abfrage ob x < 0.5 ist if (x<0.5) System.out.println("kleiner als 0.5"); // if (x<=0.5) System.out.println("kleiner gleich 0.5"); else System.out.println("größer 0.5"); // Jaff : Java für Förster 01.12.03 J. Nagel Seite 14 von 48 if (x>0.5) { System.out.println("größer als 0.5"); System.out.println("und noch eine extra Anweisung"); } } } Aufgabe: Schreiben Sie ein Programm, welches die Sterbewahrscheinlichkeit eines Baumes über einen Zufallseffekt steuert. Die Wahrscheinlichkeit, daß ein Baum im nächsten Zeitraum stirbt, soll 5 % betragen. Rufen Sie das Programm 20 x auf und notieren Sie wieviele Bäume absterben. Schleifen Ein wichtiges Element in der Programmierung ist die Möglichkeit, Anweisungen wiederholt in Schleifen auszuführen. In Java gibt es drei Schleifenanweisungen. Die Schleifen lassen sich beliebig ineinander verschachteln, so kann man mehrdimensionale Probleme einfach bearbeiten. Bei der while-Schleife wird eine Anweisung solange ausgeführt, wie ein bestimmter Ausdruck am Schleifenanfang gilt. Programm p5.java: while-Schleife Aufgabe: Das Programm soll von einer zufälligen Variablen x mit einem Startwert zwischen 0 und 200 so oft 20 abziehen, solange x > 0 ist. Das Programm soll nach jeder Subtraktion den Wert von x ausschreiben und am Ende die Anzahl der Subtraktionen mitteilen. Algorithmus: 1.) Erzeugen einer Variablen x in der eine Zufallszahl zwischen 0 und 200 gespeichert wird. 2.) Erzeugen der Zufallszahl. 3.) Erzeugen einer Zählervariable n mit dem Startwert 0. 4.) Verwenden einer while Schleife, in welcher 4.1) x um 20 subtrahiert wird. 4.2) Ausgeben des Wertes von x. 4.3) Der Zähler n um 1 erhöht wird. 5.) Ausgabe der Anzahl der Subtraktionen. Programmierung: Schreiben Sie das Programm p5.java in eine separate Datei mit einem Texteditor. // while Schleife public class p5 { public static void main (String args[]) { double x; int n = 0; // Erzeugen eine Zufallszahl zwischen 0 und 200 x=Math.random()*200.0; System.out.println("Startwert von x = "+x); while (x>=20.0) { x=x-20.0; System.out.println("Wert von x = " +x); n=n+1; } System.out.println("20 war "+n+" mal enthalten"); Jaff : Java für Förster 01.12.03 J. Nagel Seite 15 von 48 }ber } Die while-Schleife wird mit dem Wort while und einem nach folgendem konditionalen Abfrage eingeleitet. Ist die Abfrage wahr oder true wie es in der Programmierung heißt, so werden die Anweisungen, die sich im folgenden Block ({}) enthalten sind, ausgeführt. Andernfalls wird der Anweisungsblock übersprungen. Bei der while-Schleife wird immer am Anfang die Bedingung abgefragt. Berechnen Sie für Stammstücke mit Längen von 30m, 29.8m, 17.5 m wieviel Rollen mit einer Länge von 3,0 m Sie aus diesen Stammstücken schneiden können, wenn Sie ein Übermaß von 2% in der Länge berücksichtigen müssen. Die for-Schleife ist eine typische Zählerschleife, mit der sich Anweisungen n-Mal ausführen. Die for-Schleife verfügt dazu über einen Zähler vom Typ Integer, der für einen definierten Bereich durchgezählt wird. Programm p6.java: for-Schleife Aufgabe: Das Programm soll 10 mal die Zeile „Programmieren macht Spaß“ ausgeben. Algorithmus: 1.) Erzeugen einer Schleife mit einem Zähler i und einem Bereich von 1 bis 20. 1.1) Ausgabe der Zeile „Programmieren macht Spaß“ Programmierung: // for Schleife public class p6 { public static void main (String args[]) { int i=1; for (i=1;i<=20;i++) System.out.println("Programmieren macht Spass "); } } Der Ausdruck in der Anweisung in der Schleife i++ ist gleichbedeutend mit i=i+1. Sie können die Schreibweise alternativ verwenden. Es ist auch möglich den Schleifenzähler schneller z.B. um 5 zu erhöhen (i=i+5), dann würde nur jeder 5. Schritt ausgeführt. Schleifenzähler können auch rückwärts laufen. Aufgabe : Ermitteln Sie 1) nummerisch das Alter des größten Höhenzuwachses für eine Winterlinde mit den Startwerten Alter=5 und Höhe=20cm, 2) die Baumhöhe im Alter 100. Höhenwachstumsfunktion der Winterlinde: γ ln alter h α = 1.011263, β = 0.495586, γ = 96.173358 ih = β ⋅h α ih= Höhenzuwachs/a, h= Baumhöhe, alter=Alter; natürliche Logarithmus = Math.log(), Exponent = Math.exp() Verwenden Sie dazu Jahresschritte von einem ganzen Jahr. Literatur: Böckmann, Th. (1990): Wachstum und Ertrag der Winterlinde (Tilia cordata Mill) in Niedersachsen und Nordhessen. Dissertation Univ. Göttingen. S.143; Sloboda, B. (1971): Zur Darstellung von Wachstumsprozessen mit Hilfe von Differenzialgleichungen erster Ordnung. Mitt. Bad.-Württemb. Forstl. Vers. u. Forsch. Anst. 32 Jaff : Java für Förster 01.12.03 J. Nagel Seite 16 von 48 Bei der do ... while -Schleife wird am Ende der Schleife die Bedingung abgeprüft. Sie ist also ähnlich wie die while-Schleife. Der Hauptunterschied ist der, dass die Schleife auf jeden Fall einmal durchlaufen wird. Programm p7.java: do ... while-Schleife Aufgabe: Wir wollen einen Körper betrachten, der über eine Funktion aufgebaut und über eine zweite gleichzeitig abgebaut wird. Der Startwert ist 50. Der Aufbauprozess hat eine Rate von 10/Alter. Der Abbauprozess von 2*Alter. Die Simulation startet im Alter 2. In welchem Alter stirbt der Körper, wenn er mindestens einen Wert von 10 haben muss. Algorithmus: 1.) Erzeugen einer Variable in der, der aktuelle Wert des Körpers gespeichert wird. 2.) Erzeugen der Variable Alter. 3.) Beginn der while Schleife. 3.1) Berechnen des Aufbaus 3.2) berechnen des Abbau 3.3) Alter+1 3.) konditionale Abfrage, ob Körper größer Null. 4.) Ergebnisausgabe Programmierung: public class p7 { public static void main (String args[]) { double x=50; //Startwert des Körpers int alter=2; // Alter do { x=x+(10.0/alter); x=x-(2.0*alter); alter=alter+1; } while (x>=10.0); System.out.println("Anzahl der Jahre "+alter); } } Das Problem aus Programm p7 läßt sich auch mathematisch lösen. Wenn bei ähnlichen Problemen jedoch Zufallseffekte enthalten sind, kann man solche Problem nur nummerisch lösen. Theoretisch benötigt man nur einen Schleifentyp. Mit den drei Typen kann man jedoch einige Probleme leichter lösen und übersichtlicher schreiben. Mit den Befehlen break und continue kann man zusätzlich Schleifen unterbrechen. Der break Befehl bewirkt, daß eine Schleife sofort unterbrochen und verlassen wird. Bei der continue Anweisung wird der Rest des Schleifendurchlaufs nicht mehr abgearbeitet. Break und continue sollte nur in Notfällen verwandt werden, die Anwendung dieser beiden Sprachelement gilt allgemein als schlechter Programmierstil, daher finden Sie hier auch kein Beispiel. Falls bei einer do oder while Schleife die Bedingung nie erreicht wird, hört das Programm nicht auf zu rechnen. Sie können das Programm dann mit Gewalt unterbrechen, z.B. im DOS mit Strg+C. Mit der switch-Anweisung lassen sich Fälle unterschiedlich bearbeiten. Sie testet eine Integer- Jaff : Java für Förster 01.12.03 J. Nagel Seite 17 von 48 Variable im Beispiel i, ob sie einer Konstanten entspricht. Die Konstante wird mit case festgelegt. Die Bedingung wird durch einen : abgrenzt, auf den die spezielle Anweisung oder ein Anweisungsblock folgt. Jede case-Anweisung muß mit einem break; abgeschlossen werden. Programm p8.java: switch und break - Anweisung Aufgabe: Wir wollen in einer Schleife von 1 bis 10 die switch Anweisung zeigen. Wenn der Schleifenzähler 1 ist, soll Baumart 1 auf dem Schirm angezeigt werden, usw bis Baumart 3. Zusätzlich soll bei jedem Schleifendurchlauf der Wert des Schleifenzählers auf dem Bildschirm erscheinen. Algorithmus: 1.) Erzeugen einer for-Schleife von 1 bis 3 wird. 1.1) Erzeugen der switch Anweisung. 1.2) Ausschreiben des Wertes des Schleifenzählers. Programmierung: public class p8 { public static void main (String args[]) { for (int i=1;i<=10;i++) { switch (i) { case 1 : System.out.println("Baumart 1");break; case 2 : {System.out.println("Baumart 2");} break; case 3 : System.out.println("Baumart 3");break; } System.out.println("Durchlauf : "+i); } } } Aufgabe: Schreiben Sie mittels einer doppelten for-Schleife eine kleine Massentafel in Tabellenform (Volumenberechnung mit Hilfe der einfachen Zylinderformel), wobei der BHD von 15 bis 20 cm die Zeilen definiert und die Höhe von 18 bis 22 m die Spalten bestimmt. Für die Höhe und den Durchmesser sollen ganze Zahlen (Integer) verwendet werden. Arrays Zuvor haben wir gelernt, wie man Speichervariablen definieren und erzeugen kann. Stellen wir uns vor, dass man in einem Programm z.B. auf die Durchmesser von 200 Bäumen jederzeit zugreifen möchte, so wird die Definition der Variablen recht mühsam. In Java lassen sich, wie mit fast allen Programmiersprachen dafür sogenannte Arrays oder Feldvariablen definieren. Mit solchen Variablen kann man sehr einfach größere Datenmengen deklarieren und verarbeiten. Eine Array-Variable muß man sich wie einen Vektor vorstellen. Diese Vektoren können auch mehrdimensional sein. Array-Variablen werden immer mit eckigen Klammern [] gekennzeichnet. Den Speicherplatz für das Array selber muß man mit dem Schlüsselwort new bereitstellen. Auf die einzelnen Variablen des Arrays kann man über den Index, der in der eckigen Klammer (z.B. a[56]) angegeben wird, zugreifen. double a[]; //Variable a ist eine Gleikomma-Arrayvariable a = new double[1000]; //Damit stehen 1000 Variablen zur Verfügung Beachten Sie, daß Arrays in Java mit dem Index 0 beginnen. Jaff : Java für Förster 01.12.03 J. Nagel Seite 18 von 48 Programm p9.java: Array-Variablen zur Berechnung des Mittelwerts Aufgabe: Wir wollen 10 Durchmesserwerte zwischen 10 und 100 zufällig erzeugen und die Werte in einem Array speichern. Von diesen 10 Werten wollen wir den Mittelwert berechnen. Algorithmus: 1.) Erzeugen einer Zählervariable i 2.) Erzeugen eines Arrays mit 10 Speicherstellen vom Typ double. 3.) Erzeugen einer double Variable für den Durchmesser 4.) Erzeugen einer Schleife von 0 bis 9 4.1) Erzeugen der Zufallswerte für den Durchmesser 5.) Erzeugen einer neuen Schleife 5.1 Addieren der Durchmesserwerte 6. Berechnung des Mittelwertes 7.) Ausschreiben des Ergebnisses Programmierung: public class p9 { public static void main (String args[]) { int i; double bhd[]; // Definition der Array-Variable bhd bhd= new double[10]; // Bereitstellen des Array für 10 Variablen double dm=0.0; for (i=0;i<=9;i++) //Achtung der Array beginnt beim Index 0 bhd[i]=10.0+Math.random()*90.0; //zufälliger BHD zwischen 10 und 100 for (i=0;i<=9;i++) System.out.println("BHD "+(i+1)+" = "+bhd[i]); for (i=0;i<=9;i++) dm=dm+bhd[i]; dm=dm/10; System.out.println("Mittelwert : "+dm); } } Mehrdimensionale Arrays lassen sich erzeugen durch die Anweisung: double bhd[] []; bhd= new double[10][10]; Übungsaufgabe: Schreiben Sie ein Programm, mit dem Sie 20 zufällige BHD-Werte sortieren können. Berechnen Sie dann den D100 und den Dg. Es gilt, dass sich die 20 Bäume auf eine Fläche von 0.1 ha beziehen. Hinweis: Die Quadratwurzel einer Zahl erhalten Sie mit der Methode sqrt der Klasse Math ( 2.0=Math.sqrt(4.0) ). Mehr zu der Klasse Math ist später im Text beschrieben. Klassen Zweck und Aufbau Klassen sind spezielle Datentypen, die sich zum Einen aus Variablen mit verschiedenen Datentypen (sogenannten Eigenschaften) und zum Anderen aus Methoden, die sich auf die Klasse beziehen, zusammensetzen. Die Begriffe Klasse, Eigenschaft und Methoden kann man sich verdeutlichen, in dem man z.B. einmal versucht einen Hund als Klasse für ein Computerspiel abzubilden. So ein digitaler Hund hat verschiedene Eigenschaften, wie Größe, Jaff : Java für Förster 01.12.03 J. Nagel Seite 19 von 48 Gewicht, Farbe, Zähne, Schwanz etc.. Damit der digitale Hund nun auch fressen, beißen, bellen und mit dem Schwanz wedeln kann, hat er Methoden, die diese Vorgänge beschreiben. Hat man so einen digitalen Hund und erst einmal erstellt, so kann man ihn beliebig vermehren, in dem man viele Variablen oder einen Array der Klasse Hund erzeugt. Im Unterschied zu den Arrays, besteht eine Klasse nicht nur aus dem gleichen Datentyp (z.B. Integer), sondern die Eigenschaften können verschiedemste Datentypen sein. Die Klasse verfügt zusätzlich über Methoden. Da Klassen selber Datentypen sind, kann man wiederum Variablen dieser Klassen in anderen Klassen definieren. Diese Variablen heißen Instanzen einer Klasse oder auch Objekte. Im Gegensatz zu den Programmiersprachen C und Pascal ist der Programmierer nicht dafür verantwortlich, daß die Speicherbereiche, die durch Objekte belegt werden, wieder freigegeben werden, weil im Hintergrund ein sogenannter Garbage collector den Speicherplatz für die Objekte wieder frei gibt. Eine Klasse besteht allgemein aus: Modifizier class Klassenname extends Basisklasse implements Schnittstellen { Konstruktor Eigenschaftendeklarationen Methodendeklarationen } Der Modifizier ist optional, mit ihm läßt sich festlegen, ob eine Klasse z.B. public (öffentlich), abstract oder final sein soll. Klassen, die als public gekennzeichnet werden, können überall benutzt werden. Es kann in einer Quelldatei maximal eine Klasse public deklariert werden. Von abstrakten Klassen kann kein Objekt erzeugt werden, sie dienen nur als Basisklasse für die Vererbung. Von final gekennzeichneten Klassen können keine Subklassen abgeleitet werden. Hinter dem Schlüsselwort class steht der Klassenname. Die Verwendung einer Basisklasse ist optional. Mit ihr kann man der Klasse die Attribute und Methoden der Basisklasse vererben. So kann ein Försterhund z.B. von der Klasse Hund abgeleitet werden und er kann mit zusätzlichen Eigenschaften, wie „gehorcht auf Pfiff“ (ja/nein), und Methoden, wie „sucht_Wild“ oder „läuft_weg“ versehen werden. Hund wäre in diesem Fall die Basisklasse. Die Methoden können die Werte bzw. den Zustand von Eigenschaften ändern. Wenn der Hund, z.B. Wild sucht, verliert er Gewicht. Schnittstellen steht für die Namen der Interfaces, deren Eigenschaften von der Klasse realisiert werden. Unter den Attributdeklarationen sind Variablen der Klasse zu verstehen. Methoden beschreiben Funktionen. Jede Klasse verfügt automatisch über einen Standard-Konstruktor ohne Parameter. Mit der Definition eines Kontruktors können bei der Erzeugung der Klasse zur Initialisierung spezielle Aufgaben durchgeführt werden. Ein Konstruktor trägt den Namen der zugehörigen Klasse und hat keinen Rückgabewert. Den Konstruktor muß man sich als eine Methode vorstellen, die bei der Erzeugung der Klasse ausgeführt wird. Jaff : Java für Förster 01.12.03 J. Nagel Seite 20 von 48 Einfaches Klassenbeispiel Wir definieren ein einfaches forstliches Objekt, einen Baum. Dieser Baum hat die Eigenschaften: Art (Integer), Alter (Integer), Bhd (double), Hoehe (double). Vorerst wollen wir uns mit einer Methode begnügen und definieren, daß der Baum mit einer Rate von 3% wächst. Man deklariert den Baum: Aufgabe: Wir schreiben eine Klasse Baum. Der Baum hat die Eigenschaften Art, Alter, BHD und Höhe. Im Konstruktor sollen den Eigenschaften Startwerte zugewiesen werden. Die Klasse Baum soll über eine Methode wachsen verfügen. Programmierung: class baum // Diese Klasse schreiben wir in die Datei baum.java { int alter; String art; double bhd, hoehe; void baum() // Dies ist der Konstruktor { bhd=25.0; hoehe=20.0; alter=40; art = "Buche" } void wachsen () //Methode wachsen { bhd = bhd*1.03; alter= alter +1; hoehe = hoehe*1.03 } } Man kann die Klassendefinition in dieselbe Datei oder in eine eigene Datei schreiben. Im zweiten Fall muß die Datei aber denselben Namen wie die Klasse haben, in diesem Fall baum.java. Achten Sie unbedingt auf die Gross- und Kleinschreibung; auch die muß übereinstimmen. Die Klassendatei baum.class können Sie nicht mit Java starten, denn Sie verfügt über keine Methode vom Typ main. Dafür kann man die Klasse baum in verschiedenen Programmen nutzen. Im folgenden Programm p10.java wird die Klasse baum verwendet. Aufgabe: Ein Baum der Klasse baum.class soll 10 Jahre lang wachsen. Wir wollen die Veränderung von Alter, BHD und Höhe ausschreiben. Programmierung: Programm p10.java: Verwendung einer Klasse public class p10 { public static void main (String args[]) { // Das Programm p10 hat keinen speziellen Konstruktor // Definieren wir eine Variable Buche1 der Klasse baum baum Buche1=new baum(); // Den Konstruktor aufrufen und die Startwerte setzen Jaff : Java für Förster 01.12.03 J. Nagel Seite 21 von 48 Buche1.baum(); // Nun betrachten wir die Entwicklung während der nächsten 10 Jahre for (int i=1;i<=9;i++) { Buche1.wachsen(); System.out.println("Alter "+Buche1.alter+" BHD "+Buche1.bhd+ " Hoehe "+Buche1.hoehe); } } } Ein neues Objekt der Klasse Baum mit dem Namen Buche1 erzeugt man mit der Anweisung. baum Buche1=new baum(); Wenn Sie die Datei p10 starten, so muß java die Klasse Baum zur Verfügung stehen. Die Klasse baum.class könnte auch in der Datei p10.java stehen. Da man die Klassen aber häufig auch in anderen Programmen verwenden will, schreibt man die Klassen gewöhnlich in eigene Dateien. Die Klassen müssen im selben Unterverzeichnis liegen, ansonsten muß man beim Starten des Programms java die Option –cp (Classpath) setzen. Mehrfach genutzte Klassen können, wie z.B. die mitgelieferten Klassen, in einer Bibliothek zusammengefaßt werden. Dazu muß man den Pfad in der Systemvariablen Classpath definieren. Es gibt einige Java Programmieroberflächen (z.B. Jbuilder von Borland oder Forte von Sun), die einem ganz wesentlich bei der Verwaltung der Klassen helfen. Jaff : Java für Förster 01.12.03 J. Nagel Seite 22 von 48 Der Sinn der Klassen ist eine Bündelung von Daten und Methoden. Damit erhalten wir eine bessere Ordnung. Die Klassen lassen sich in anderen Programmen oder Programmteilen wiederverwenden. In Klassen kann man innere Vorgänge verstecken, wodurch die Klassen besser zu warten sind, ohne daß im idealen Fall das Programm beeinflusst wird. Stellen wir uns nur einmal vor, wir wollten die o.g. Routine, die das Wachstum beschreibt, begrenzen, damit die Bäume nicht in den Himmel wachsen. Wir könnten das mit einer einzigen Änderung in der Klasse baum.java erreichen. Diese Änderung würde sich dann in allen Programmen auswirken, die auf die Klasse baum.class zugreifen. Aufgabe: Schreiben Sie ein Programm, welches die Klasse Baum nutzt. Fügen Sie der Klasse eine neue Methode zur Berechnung des Volumens hinzu (s. Volumenfunktion). Schreiben Sie einen Baum (BHD=20cm, Alter=10, Art=211, Höhe=15m) über 20 Jahre fort und geben Sie die Werte aller Variablen aus. Durch Vererbung lassen sich Klassen erweitern und somit um neue Eigenschaften und Methoden ergänzen. Denken wir uns, daß wir jetzt einen Nadel- und einen Laubbaum mit einer Baumkrone benötigen. Beim Laubbaum wird die Krone durch eine Kugel und deren Radius beschrieben. Die Krone des Nadelbaumes ergibt sich aus einem Kegel, der über die Kronenbreite und den Kronenansatz definiert wird. In diesem Fall könnte man zwei neue Klassen Nbaum und Lbaum definieren. Ein besserer Weg ist die Klasse baum zu verwenden und den Nadel- und Laubbaum über Vererbung und Erweiterung zu definieren. Im nächsten Beispiel erweitern wir die Klasse baum in eine Klasse baummk (mit Krone). Die Erweiterung wird mit dem Schlüsselwort extends durchgeführt. Programm p11.java: Anwendung und Erweiterung einer Klasse Aufgabe: Die Klasse Baum verfügt über einige Eigenschaften und Methoden, diese sind aber für unsere neue Aufgabe nicht ausreichend. Wir möchten, die Kronenbreite eines Baumes mitbetrachten. Die Kronenbreite soll aus dem BHD abgeleitet werden (kb=1.388+0.18*BHD). Man kann nun eine ganz neue Klasse schreiben, oder die alte Klasse baum verwenden und erweitern. Wir wollen den zweiten Fall zeigen. Programmierung: // Erweitern der Klasse baum, diesmal // in der gleichen Datei, wie das Hauptprogramm class baummitkb extends baum { double kb ; //neue Variable für den Kronenbreite // neue Methode zur Berechnung der Kronenbreite void calculateKb() { kb=1.388+0.18*bhd; } // neue weitere Methode, die den Kronenradius ausgibt double getKradius() { return kb/2.0; } } public class p11 Jaff : Java für Förster 01.12.03 J. Nagel Seite 23 von 48 { public static void main (String args[]) { // Definieren wir eine Variable Buche 1 baummitkb Buche1=new baummitkb(); // Startwerte setzen Buche1.baum(); Buche1.calculateKb(); System.out.println(Buche1.art+" BHD "+Buche1.bhd+" Kronenbreite "+Buche1.kb); System.out.println(" Kronenradius "+Buche1.getKradius()); } } Wenn Sie die Klasse p11.java mit javac übersetzen, entstehen die zwei class baummitkb.class und p11.class Dateien. Beide Dateien werden benötigt, um das Programm auszuführen. Aufgabe: Erweitern Sie die Klasse baum um die Standpunktkoordinaten x, y und z eines Baumes und zeigen Sie die Funktion in einem kleinen Beispiel. Die nächste Anwendung zeigt, wie die Klasse baum in der Klasse wald als Array-Variable verwendet wird. Zu beachten ist in diesem Fall, daß die Zeile baum ba[]=new baum[100]; nur Zeiger zur Verfügung stellt. Der eigentliche Speicherplatz für die Array-Variable wird erst durch die Zeile ba[nbaum]=new Baum(); bereitgestellt. Man sieht, daß das Programm mit den zwei Klassen sehr klar gegliedert ist. Die Klasse baum behandelt die Operationen auf der Einzelbaumebene, während die Klasse wald die Berechnungen auf der übergeordneten Ebene des Waldes behandelt. Das Hauptprogramm stellt lediglich die Methoden zum Ansprechen der beiden Klassen dar. Programm p12.java: Verwendung zweier Klassen Aufgabe: Wir wollen eine Eichenwald schaffen. Dazu wollen wir eine Klasse definieren, die eine Eiche beschreibt und eine weitere Klasse die einen Wald mit Eichen beschreiben kann. Die Objekte der Klasse Eiche sollen als Array in der Klasse Wald zur Verfügung stehen. Die Klasse Eiche soll 3 Methoden haben: 1.) setStartwerte für Alter, BHD und Höhe. 2.) Eine Methode wachsen. 3.) Eine Methode zur Volumenberechnung. Die Klasse wald soll aus Objekten der Klasse eiche bestehen. Diese werden in einem Array organisiert. Die Klasse Wald verfügt wiederum über 3 Methoden: 1.) addEiche um Eichen zum Wald hinzuzufügen. 2.) Eine Methode wachsen, die alle Eichen des Waldes wachsen läßt. 3.) Eine Methode um das Volumen aller Eichen abzufragen. Im Hauptprogramm wird nun ein Wald erzeugt. Diesem Wald werden Eichen hinzugefügt. Die Durchmesser- und Höhenwerte werden mit einer Zufallskomponente versehen. Zur Kontrolle schreiben wir die Werte unserer Eichen aus. Dann lassen wir den Eichenwald 20 Jahre lang wachsen und notieren jedesmal das Holzvolumen im Wald. Programmierung: class eiche { Jaff : Java für Förster 01.12.03 J. Nagel Seite 24 von 48 int alter; double bhd,hoehe,volumen; // Diese Methode setzt die Startwerte eines Baumes void setStartwerte(int alt,double d, double h) { alter=alt; bhd=d; hoehe=h; volumen=volumenNachFunktion(bhd,hoehe); } // Methode wachsen läßt die Eiche wachsen void wachsen() { bhd=bhd*1.03; hoehe=hoehe*1.05; volumen=volumenNachFunktion(bhd,hoehe); } // double volumenNachFunktion (double d,double h) { double pi=3.141592; return pi*(d/200)*(d/200)*h*(0.4786-(1.0111/d)+(2.1042/h)-(203.2/(d*h*h))); } } class wald { int nbaum=0; //Anzahl der Bäume int i; eiche ei[]=new eiche[100]; //Einzelbäume der KLasse Baum s.o void addEiche(int alt, double d,double h) { ei[nbaum]=new eiche(); ei[nbaum].setStartwerte(alt,d,h); nbaum=nbaum+1; } void wachsen() { for (i=0; i<nbaum; i++) ei[i].wachsen(); } double gesamtVolumen() { double v; v=0.0; for (i=0; i<nbaum; i++) v=v+ei[i].volumen; return v; } } public class p12 { public static void main (String args[]) { wald w=new wald(); for (int i=0;i<10;i++) { w.addEiche(60,25+5.0*Math.random(),20+10.0*Math.random()); } // nur zur Kontrolle for (int i=0;i<w.nbaum;i++) System.out.println(w.ei[i].alter+" "+w.ei[i].bhd+" "+w.ei[i].hoehe); // lassen wir den Eichenwald mal wachsen Jaff : Java für Förster 01.12.03 J. Nagel for (int i=0; i<20; i++) { w.wachsen(); System.out.println("Volumen } Seite 25 von 48 : "+w.gesamtVolumen()); // Kommentar } } Erweitern Sie die Klasse eiche durch Vererbung in eine Klasse meinEiche und fügen Sie als zusätzliche Eigenschaften eine Wertvariable hinzu, die die Werte 1, 2, 3 und 4 annehmen kann. Hüllklassen und Umwandeln von Datentypen Für den Anfänger in Java ist es oft eine große Schwierigkeit, wenn er einen Datentyp in einen anderen umwandeln muss. Stellen wir uns vor, wir lesen Daten als Zeichenkette (String) ein. Nun wollen wir aber Teile einer solchen Zeichenkette als Zahl verwenden. Dazu müssen wir die Zeichenkette in eine Zahl umwandeln. Dies klingt recht einfach, ist in Java aber z.T. etwas verwirrend, da es für die primitiven Klassen (double) es sogenannte Hüllklassen gibt. Die Hüllklassen verfügen über eine Anzahl von Methoden für den Zugriff auf die „umhüllende“ Variable. Mit diesen Methoden kann man z.B. Zeichenketten (Strings) in Integer oder Gleitkommazahlen verwandeln. Primitiver Datentyp Hüllklasse boolean char byte short int long float double Boolean Character Byte Short Integer Long Float Double So ist eine Variable vom Typ double der primitive Datentyp und nicht gleich dem Datentyp Double, welcher die Hüllklasse ist. Man muß hier wie immer in Java auf die Groß- und Kleinschreibung achten. Alle Hüllklassen haben die Methode toString(). Mit dieser Methode kann man den Wert des Hüllobjektes als Zeichenkette ausgeben. Die numerischen Hüllobjekte verfügen zu dem über die Methode valueOf(String s). Die Methode kann eine Zeichenkette in den numerischen Datentyp umwandeln. Programm p13.java: Verwendung zweier Klassen Aufgabe: In dieser Anwendung soll die Umwandlung von Datentypen gezeigt werden. Programmierung: // Umwandlung von Datentypen class p13 { public static void main (String args[]) { // Definition einiger Datentypen double x = 55.5; int n = 10; Jaff : Java für Förster 01.12.03 J. Nagel Seite 26 von 48 String s1 = "88"; String s2 = "99.9"; // Umwandlung von x in ein int int nvonx = (int) (x); System.out.println("Umwandlung von double in int "+x+" "+nvonx); // Umwandlung s1 in ein int int nvons1 = Integer.parseInt(s1); System.out.println("Umwandlung von String in int "+s1+" "+nvons1); // Ein Test System.out.println("Addition der neuen Integer "+(nvonx+nvons1)); // Umwandlung s2 in ein double double dvons2 = Double.parseDouble(s2); System.out.println("Umwandlung von String in double "+s2+" "+dvons2); // Ein Test System.out.println("Multiplikation von dvons2 mit 10.0 = " +(10.0*dvons2)); // Umwandlung double in eine Zeichenkette String sneu = Double.toString(x); sneu="Zeichenkette"+sneu; System.out.println("Umwandlung von double in String "+sneu); // Umwandlung int in eine Zeichenkette String sneu2 = Integer.toString(n); sneu2=sneu+sneu2; System.out.println("Umwandlung von int in String "+sneu2); } } Klasse Math Ganz beiläufig hatten wir schon einige Methoden der Klasse Math kennengelernt. Diese mitgelieferte Klasse enthält zahlreiche fertige mathematische Funktionen sowie die beiden Konstanten E (Eulersche Zahl e) und PI die Kreiskonstante. Methode Erklärung Typ abs(Typ x) Typ min(Typ x, Typ y) Typ max(Typ x, Typ y) double ceil(double x) double floor(double x) int round(Typ x) double sqrt(double x) double pow(double x, double y) double exp(double x) double log(double x) double sin(double x) double cos(double x) double asin(double x) double acos(double x) double tan(double x) double atan(double x) double random() double PI() Absolutbetrag von x. Typ steht für int, long, float, double Minimum von x und y. Maximum von x und y. liefert die kleinste ganze Zahl > oder = x liefert die größste ganze Zahl < oder = x rundet auf eine ganze Zahl Quadratwurzel von x Potenz xy ex natürlicher Logarithmus von x Sinus von x Cosinus von x Arcussinus von x Arcuscosinus von x Tangens von x Arcustangens von x Zufallszahl >=0 und <=1 Zahl PI Jaff : Java für Förster 01.12.03 J. Nagel Seite 27 von 48 Klasse DecimalFormat Die Klasse DecimalFormat aus java.text kann zur Darstellung und Umwandlung von Dezimalzahlen verwendet werden. Mit DecimalFormat erzeugt man ein Objekt und übergibt diesem ein bestimmtes Muster. Für das Muster können folgende Zeichen benutzt werden: # Ziffer, führende Nullen werden nicht ausgegeben 0 Ziffer, führende Nullen werden angezeigt . Decimalpunkt , Symbol für die Tausendertrennung % Darstellung als Prozentzahl DecimalFormat f = new DecimalFormat(“##,##0.00“); System.out.println(f.format(2101.879)); // Die Ausgabe wäre 2.101,88 Die Verwendung von DecimalFormat wird in dem Programm p16 gezeigt. Aufgabe: Schreiben Sie eine Anwendung mit der Sie die Einzelbaumgrundfläche von zehn zufällig erzeugten Bäumen (BHD zwischen 7 und 77cm) berechnen. Geben Sie das Ergebnis auf eine Stelle hinter dem Komma in cm² aus. Verwenden von Klassen aus dem Internet Im Internet finden Sie zahlreiche Java Programme und java Klassen, die Sie für die Lösung Ihrer Probleme verwenden können. Unter http://treegross.sourceforge.net wird von der Niedersächsischen Forstlichen Versuchsanstalt eine Komponente zur Lösung waldwachstumskundlicher Probleme bereitgestellt. Die Komponente treegross.jar (Tree Growth Open Source Software) beinhaltet das komplette Waldwachstumsmodell BWINPro. Einige der in treegross.jar enthaltenen Klassen, z.B. für die Volumenberechnung und die Ermittlung der Schaftform, lassen sich auch einzelnd nutzen. Im folgenden wird die Klasse volumebynfv vorgestellt. Diese Klasse enthält die gängigen Formzahl und Volumenfunktionen für Niedersachsen. Jaff : Java für Förster 01.12.03 J. Nagel Seite 28 von 48 Abbildung: Beschreibung der Klasse volumebynfv aus dem Packet treegross.jar im Netz durch Javadoc Im Internet können wir eine Beschreibung zu der Klasse volumebynfv finden. Wichtig ist hier die Erklärung des Konstruktors. Für ihn werden keine Übergabeparameter benötigt. In der Methoden Summary finden wir die Methode volume. Diese liefert das Volumen eines Baumes als double zurück, wenn der Baumartencode, der BHD und die Höhe übergeben werden. Den Sourcecode der Klasse volumebynfv kann man sich auch aus dem Repository laden. Im Kopf für die Klasse finden wir folgende Erklärung: /** calculates the volume by volume or form function. Parameters: species code Lower Saxony, if species code < 100 then the number is taken for the volume/form function; dbh [cm]; height [m]. The method returns the volume in cubic meters */ double volume(int spcode,double d,double h) Mit anderen Worten können wir die Methode volume der Klasse volumebynfv nutzen, um das Volumen eines Baumes zu berechnen. Im folgenden Beispiel wird die Verwendung der Klasse volumebynfv deutlich. Programm p13a.java: Verwendung einer Klasse Jaff : Java für Förster 01.12.03 J. Nagel Seite 29 von 48 //Verwendung der Klasse volumebynfv zur Berechnung des Volumens // public class p13a { public static void main (String args[]) { int baumartencode =211; // 211 ist der Code für Buche in Nds. double bhd= 20.0; // Der Baum soll einen BHD von 20 cm haben double hoehe= 19.5; // Der Baum soll eine Hoehe von 19,5m haben double volumen =0.0; // in diese Variable soll der Volumenwert gespeichert werden // volumebynfv vnfv = new volumebynfv(); //Erzeugen des Objects volumebynfv volumen=vnfv.volume(baumartencode,bhd,hoehe); // Aufruf der Methode volume System.out.println("Das Volumen ist : "+volumen); } } Wenn man das Programm p13a.java mit javac kompiliert, muss Datei volumebynfv.class im gleichen Verzeichnis vorhanden sein. Befindet sie sich in einem anderen Verzeichnis, so muss der classpath richtig gesetzt werden. Alternativ kann man auch die Datei treegross.jar verwenden, die die Datei volumebynfv.class neben anderen enthält. Diese Datei muss ebenfalls über den classpath zur Verfügung gestellt werden. Aufgabe: Berechnen Sie die Länge und den Mittendurchmesser für ein Douglasienstammstück (Baumartencode = 611), welches von einem Baum mit einem Durchmesser von 60 cm und einer Höhe von 35m stammt. Das Stamm wurde in einer Höhe von 0,3m gefällt und soll in einem Stück bis zu einem Zopfdurchmesser von 20cm ausgehalten werden. (Verwenden Sie als Schaftformmodell die Klasse taperbysloboda aus dem treegross.jar, verwenden Sie die Methode findd() und diameter()). Lesen und Schreiben aus Dateien Eine wichtige Funktion, die man beim Programmieren beherrschen muß, ist das Lesen und Schreiben von Dateien. Erst dann kann das Programm in den meisten Fällen zu einem wertvollen Werkzeug werden. Aber manchmal ist es auch schon genug, wenn man sich ein kleines Programm schreiben kann, welches Daten, die in Spalten organisiert sind, in einer anderen Reihenfolge ausgeben kann. In diesem Kapitel soll das einfache Schreiben und Lesen aus Dateien erklärt werden. In den vorhergehenden Beispielen haben wir schon die Methode println() der Klasse System.out kennengelernt. Als erstes wollen wir aus einer Textdatei zeilenweisen lesen können. Die notwendigen Klassen für den BufferedReader befinden sich in dem Paket java.io.*. Daher muß dieses zuvor mit import angegeben werden. Mit import werden Klassen aus Paketen am Beginn der Datei dem Programm bekannt gegben. BufferedReader verfügt über eine Methode in.readLine(), über welche der String mit jeweils einer Zeile übergeben wird. Bitte versuchen Sie nicht alle Einzelheiten des BufferedReader zu verstehen. Hier werden vordefinierte Klassen verwendet und wenn man diese wie in dem Beispiel anwendet, kann man Datenzeilen lesen. Wichtig ist nur zu wissen, dass wir dem Reader den Namen in gegegeben haben und wo wir den Dateinamen Jaff : Java für Förster 01.12.03 J. Nagel Seite 30 von 48 testdat.txt anbringen können, damit wir aus einer bestimmten Datei lesen können. Das Lesen aus einer Datei funktioniert nur, wenn wir auch das Abfangen von Fehlern zu lassen. Dafür gibt es try {} und catch {}. Kommt es im Block von try zu einem Systemfehler, wie wenn z.B. die Datei nicht exisiert, dann wird der Block catch ausgeführt. Die zulesende Datei muß im selben Verzeichnis stehen, ansonsten muß das Verzeichnis mit dem Dateinamen angegeben werden. Programm p14.java: Zeilenweises Lesen einer Textdatei Aufgabe: Es sollen die Zeilen einer Textdatei zeilenweise gelesen werden. Programmierung: //Zeilenweise lesen aus einer Datei test.dat import java.io.*; public class p14 { public static void main (String args[]) // Das Lesen aus Dateien benötigt try und catch für den // Fall, dass es Fehler geben könnte Jaff : Java für Förster 01.12.03 J. Nagel Seite 31 von 48 { try { // Die folgenden 4 Zeilen sind noetig um einen FileInputStream zu erzeugen // Die dafuer notwendigen Klassen stammen aus dem Paket java.io // Sie sollten nicht zuviel über den Sinn der Zeilen zweifeln, wichtig ist // das wir zeilenweise lesen koennen und wissen, wo wir den Dateinamen eingeben BufferedReader in= new BufferedReader( new InputStreamReader( new FileInputStream("testdat.txt"))); while (true) { // Einlesen einer Zeile in die Variable s String s=in.readLine(); // wenn s keinen Wert hat ist das File zu Ende if (s==null) break; // ausschreiben von s System.out.println(s); } } // catch wird ausgelöst, wenn es einen Fehler unter try gibt catch (Exception e) { System.out.println(e); //Ausschreiben der Fehlermeldung } } } Jetzt stellt man sich sicher die Frage, wie wir an unsere Zahlen, die wir zeilenweise eingelesen haben, herankommen. Nun, dies ist ganz einfach. Man kann eine String-Variable in Teilstrings oder Substrings zerlegen. Auch diese Funktion gibt es bei fast allen Programmiersprachen. Den Teilstring kann man dann in eine Zahl verwandeln. Die Klasse String verfügt dazu über die Funktion substring(n,m), wobei n und m Integer sind und die Position von und bis angeben. Programm p15.java : Verarbeiten der eingelesenen Zeilen Aufgabe: Der Durchmesser steht in unserer Datei testdat.txt auf der Spalte 7 bis 11. Diesen wollen wir zeilenweise lesen und dann als Radius ausgeben. Programmierung: import java.io.*; public class p15 { public static void main (String args[]) { double bhd=0.0; String subs; try { BufferedReader in= new BufferedReader( new InputStreamReader( new FileInputStream("testdat.txt"))); while (true) { String s=in.readLine(); Jaff : Java für Förster 01.12.03 J. Nagel Seite 32 von 48 if (s==null) break; // Schreiben der eingelesenen Zeile s System.out.println(s); // speichern des Teilstrings 7.bis 11. Zeichen nach subs subs=s.substring(7,11); System.out.println("Teilstring: "+subs); // Umwandlung des Teilstrings ss in eine double-Variable bhd=Double.parseDouble(subs); double radius=bhd/2.0; System.out.println("Radius : "+radius); } } catch (Exception e) { System.out.println(e); } } } Aufgabe: Schreiben Sie ein analoges Programm, welches folgende Textzeilen aus einer Datei lesen kann. Geben Sie dazu die Daten in eine Datei ein.: Baumart, BHD, Höhe Fi 20.0 28.0 Bu 22.0 32.0 Fi 24.0 32.0 Geben Sie die Mittelwerte von BHD und Höhe aus. Nun möchten wir gerne unsere Daten wieder in eine Datei ausschreiben können. Im Prinzip ist das nicht viel anders, als wir es bereits durch die Ausgabe auf die Kommandozeile gewohnt sind. Dazu möchten wir die Variable BHD in einem besonderen Format ausgeben und zwar derart, daß sie mit 3 Stellen hinter dem Komma angezeigt wird. Zum Schreiben in ein Datenfile muß man zunächst einen OutputStream deklarieren. Diesen OutputStream verbinden wir mit der Klasse PrintWriter. Die Klasse PrintWriter verfügt über eine Funktion println() mit der man den Text in eine Datei über den OutputStream schreiben kann. Am Ende des Programmes muß man dann noch die zum Schreiben geöffnete Datei geschlossen werden. Dies geschieht mit der Funktion close() des PrintWriter. - Zahlen kann man in Java mit der Klasse NumberFormat in ein bestimmtes Format umwandeln. Zunächst muß man sich ein Objekt der Klasse NumberFormat deklarieren und über die Funktion getInstances() initialisieren. Mit dieser Methode werden die Einstellungen von Windows bezüglich der Darstellung von Zahlen übernommen. Mit den Funktionen setMaximumFractionDigits und setMinimumFractionDigits läßt sich die minimale und die maximale Zahl der Nachkommastellen festlegen. Die Variable BHD wird mit der Funktion format() der Klasse NumberFormat dann umgewandelt. Für die Klasse NumberFormat müssen aber die Packete java.text.* und java.util.* vorher importiert werden. Programm p16.java : Lesen und Schreiben einer Datei Aufgabe: Wir lesen im nächsten Programm wieder den BHD ein. Diesmal wollen wir jedoch die Grundfläche in eine weitere Datei namens ausgabe.txt schreiben. Dafür verwenden wir einen OuputStream, den wir mit einem PrintWriter verknüpfen. Um die Ausgabe in ein Format zu Jaff : Java für Förster 01.12.03 J. Nagel Seite 33 von 48 zwingen und so nur 3 Nachkommastellen angezeigt zu bekommen, benutzen wir die Klasse number mit der Methode format. Vorher muss mit den Methoden setMaximumFractionDigits und setMinimumFractionDigits noch die Anzahl der Nachkommastellen festgelegt werden. Programmierung: // Lesen und Schreiben von Dateien import java.io.*; import java.text.*; import java.util.*; public class p16 { public static void main (String args[]) { double bhd=0.0; String subs; NumberFormat number=NumberFormat.getInstance(); number=NumberFormat.getInstance(new Locale("en","US")); try { BufferedReader in= new BufferedReader( new InputStreamReader( new FileInputStream("testdat.txt"))); OutputStream os=new FileOutputStream("ausgabe.txt"); PrintWriter out= new PrintWriter(new OutputStreamWriter(os)); while (true) { String s=in.readLine(); if (s==null) break; // Schreiben der eingelesenen Zeile s System.out.println(s); // speichern des Teilstrings 7.bis 11. Zeichen nach subs subs=s.substring(7,11); System.out.println("Teilstring: "+subs); // Umwandlung des Teilstrings ss in eine double-Variable bhd=Double.parseDouble(subs); double g=Math.PI*Math.pow(bhd/200.0,2.0); number.setMaximumFractionDigits(3); number.setMinimumFractionDigits(3); System.out.println("formatiert:"+number.format(bhd)); System.out.println("Grundflaeche in qm : "+number.format(g)); //Auschreiben des doppelten von BHD und ss out.println(bhd+" "+g); } out.close(); } catch (Exception e) { System.out.println(e); } in.close(); // } } Aufgabe: Modifizieren Sie das Programm p16 so, daß neben dem Durchmesser auch die Grundfläch des Baumes in cm² ausgegeben wird. Dazu benutzen Sie bitte die Methode Power der Jaff : Java für Förster 01.12.03 J. Nagel Seite 34 von 48 Klasse Math. Die Grundfläche sollte mit einer Stelle hinter dem Komma ausgeschrieben werden. Geben Sie den Text diesmal so aus, dass die Werte durch ein Semikolon getrennt werden. Abschließend wollen wir uns noch einmal mit der Verarbeitung von Daten die in Textdateien gespeichert sind beschäftigen. Bei fast allen Programmen gibt es eine Export Funktion, mit der man sogenannten unformatierten Text schreiben kann. Ohne es Ihnen bewußt war, haben Sie dies in der Übungsaufgabe gemacht, nämlich als Sie die Werte durch ein Trennzeichen von einander getrennt haben. Auch aus z.B. Excel kann man solche Textdateien erstellen, in denen die Werte nur durch ein Trennzeichen getrennt sind (Speichern unter *.csv). Diese Dateien kann man übrigens auch importieren! Ein häufiges Problem ist dann aber, dass die Programme als Dezimaltrennzeichen das Symbol verwenden, welches in der Ländereinstellung Ihres Rechners angegeben ist. Sprich in Deutschland wir als Dezimaltrennzeichen das Komma verwendet, in vielen anderen Ländern der Punkt. Bei der Erstellung von Programmen muss man dies beachten, damit es nicht zu einem Absturz des Programmes kommt. Im folgenden wird daher ein kleines Programm gezeigt, dem es egal ist, ob das Dezimalzeichen ein Komma oder ein Punkt ist. Es werden einfach alle Kommatar in Punkte verwandelt. Darüber hinaus wird ein Verfahren gezeigt, wie man die eingelesene Textzeile elegant zerlegen kann, ohne zuerst die Spaltenbreiten abzählen zu müssen. Programm p17.java : Ersetzen von einem Zeichen mittels eines Programms Aufgabe: Wir lesen eine Datei test2.txt. In dieser sind Werte mittels eines Trennzeichen von einander getrennt. Darüber hinaus wurde in der Datei als Dezimaltrennzeichen ein Komma verwendet. Wir wollen diese Daten einlesen und auf den Bildschirm schreiben. Programmierung: // Lesen und Schreiben von Dateien import java.io.*; import java.util.*; //noetig fuer den StringTokenizer public class p17 { public static void main (String args[]) { String art=""; double bhd=0.0;double h=0.0;int alter=0; try { BufferedReader in= new BufferedReader( new InputStreamReader( new FileInputStream("test2.txt"))); // Festlegen des Trennzeichens StringTokenizer stx; String delim=";" ; while (true) { String s=in.readLine(); if (s==null) break; // Hier werden alle Punkte des Strings durch ein Komma ersetzt s=s.replace(',','.'); System.out.println(s); stx= new StringTokenizer(s,delim); art=stx.nextToken(); Jaff : Java für Förster 01.12.03 J. Nagel Seite 35 von 48 alter=Integer.parseInt(stx.nextToken()); bhd=Double.parseDouble(stx.nextToken()); h=Double.parseDouble(stx.nextToken()); System.out.println("Zerlegt "+art+" Alter "+alter+" BHD "+bhd+" H "+h); } System.out.println(); } catch (Exception e) { System.out.println(e); } } } Jaff : Java für Förster 01.12.03 J. Nagel Seite 36 von 48 Die Klasse StringTokenizer stammt aus dem Paket java.util.* . Nachdem man die Zeichenkette der Klasse StringTokenizer übergeben und das Trennzeichen festgelegt hat, kann man die Zeichenketten zwischen den Trennzeichen komfortabel mit der Methode nextToken() erhalten. Java API In den vorher angeführten Beispielen haben wir bereits kennengelernt, daß die J2SE fertige Klassen wie z.B. PrintWriter, Math und NumberFormat enthält. Für Java gibt es in Wirklichkeit einige Hundert vordefinierte Klassen. Sie bilden das API (Application Programming Interface). Die Klassen sind dabei in einzelnen Paketen zusammengefasst. Die Tabelle zeigt einige der wichtigsten Pakete. java.awt java.beans java.io java.lang java.math java.net java.rmi java.security abstract windowing toolkit. Es enthält die Klassen zur Grafikausgabe und zur Erzeugung von Benutzeroberflächen. Fertige Elemente zur graphischen Programmierung Ein- und Ausgabe von Dateien, Netz und anderen Quellen. Dieses Paket wird immer geladen und enthält string-Funktionen unterstützt im Umgang mit langen Zahlen Kommunikation über das Internet Zugriff auf andere Rechner und von anderen Programmen Verschlüsselung Diese Klassen werden mit dem Import-Befehl dem Programm zugänglich gemacht. Beschrieben sind die Klassen in der Dokumentation. Öffnen Sie dazu die Datei ...\docs\api\index.html. Sie können diese Datei natürlich nur öffnen, wenn Sie die Dokumentation in diesen Bereich installiert haben. Suchen Sie in dem Fenster unter all Classes in der alphabetischen Liste den Begriff PrintWriter und klicken Sie ihn an. Nun erhalten Sie eine genauere Beschreibung dieser Klasse. Wollen wir einen PrintWriter erstellen, so benötigen wir als Argument einen OutputStream. Sehen wir uns den OutputStream an so wird uns dort mitgeteilt, daß es sich um eine übergeordnete Klasse des FileOutputStreams handelt, welche als Argument einen String mit dem Filenamen benötigt. Genau dies haben wir in beiden Befehlszeilen OutputStream os=new FileOutputStream("ausgabe.txt"); und PrintWriter out= new PrintWriter(new OutputStreamWriter(os)); des Programms p16 erklärt. Unter PrintWriter werden dann auch die Funktionen println(), print() und close() der Klasse PrintWriter beschrieben. Grafik Bisher haben wir die wichtigsten Programmierelemente kennengelernt, mit denen man forstliche Probleme bearbeiten könnte. Aber die Programme sehen auf dem Bildschirm durch die reine Textausgabe recht bescheiden aus. Moderne Programme verfügen über eine graphische Oberfläche in Form von Fenstern bzw. eines GUI (Graphical User Interface). Die Programmierung solcher Oberflächen wollen wir im Folgenden kennenlernen. Das Java Paket AWT ermöglicht es uns, relativ einfach solche Oberflächen zu erzeugen und sie auf unsere Bedürfnisse anzupassen. Es gibt noch ein zweites moderneres Paket, um Java Fenster zu erzeugen, welches wir in einem späteren Projekt kennenlernen werden. Sie werden aber Jaff : Java für Förster 01.12.03 J. Nagel Seite 37 von 48 feststellen, daß der Aufwand für die Programmierung der Oberfläche weit höher ist, als der den Sie gewöhnlich für Ihre Berechnungen aufwenden müssen. Programm p18.java : Einfache Definition eines Fensters import java.awt.*; public class p18 { public static void main (String args[]) { Frame fenster=new Frame(); fenster.setSize(300,300); fenster.setVisible(true); } } Im Programm p18 wird zuerst das AWT-Paket importiert. Danach definieren wir das Objekt fenster der fertigen Klasse Frame(). Mit der Methode setSize läßt sich die Fenstergröße bestimmen, in diesem Fall 300 mal 300 Bildpunkte. Für die Anzeige muß das Programm noch mit setVisible sichtbar gemacht werden. Das Programm zeigt ein leeres Fenster, was sich aber nicht schließen läßt. Dies kann man im Dos-Fenster nur durch gleichzeitige Eingabe der String und der C-Taste erreichen. Das Dos-Fenster muß allerdings aktiv sein. Im weiteren Verlauf werden wir kennenlernen, wie wir das Fenster über den Knopf schließen können. Programm p19.java: Einfaches Fenster mit Text import java.awt.*; public class p19 { public static void main (String args[]) { Frame F=new Frame(); F.setSize(300,300); F.setVisible(true); Graphics g=F.getGraphics(); g.drawString("Eine Grafik",50,50); } } Programm p19 zeigt eine leichte Erweiterung des Programmes. In diesem Fall wird auf der graphischen Oberfläche der Text „Eine Grafik“ an der Position x=50 und y=50 ausgegeben. Beachten Sie, das eine Position x=0 und y=0 auf einem graphischen Bildschirm immer die linke obere Ecke meint. Insofern muß man die y-Koordinate immer erst transformieren. Dieses Programm entspricht nun nicht der Idee, der objektorientierten Programmierung. Es könnte nämlich passieren, daß die Methode drawString den Text zu einem Zeitpunkt schreiben will, an dem unsere Klasse p19 noch nicht erzeugt ist. Aufgabe: Positionieren Sie in einem Fenster (Pixelgröße 500x250), wie p19 einen Text in der linken oberen Ecke und der unteren Hälfte. Programm p20.java : Grafik mit Text, Linien und Kreis Jaff : Java für Förster 01.12.03 J. Nagel Seite 38 von 48 /* JAFF = Java fuer Foerster Ereignis orientierte Programmierung: Grafikfenster */ import java.awt.*; class GFenster extends Frame { public void paint(Graphics g) { g.drawString("Waldsimulator",100,100); Dimension d=getSize(); int w=d.width, h=d.height; //Zeichnen zweier Linien g.drawLine(0,0,w-1,h-1); g.drawLine(0,h-1,w-1,0); // Zeichnen eines Rechtecks g.drawRect(0,0,w-1,h-1); // Farbe einstellen g.setColor(Color.red); // Einen gefüllten Kreis in rot zeichnen g.fillOval(w/2,h/2,30,30); } } public class p20 { public static void main (String args[]) { Frame F=new GFenster(); F.setSize(500,500); F.setVisible(true); } } Im Fall von p20 wurde ein objektorientierter Ansatz gewählt. Zuerst wir die Klasse Frame zu der Klasse GFenster erweitert. Wir definieren die Variable d vom Typ Dimension und können über die Methode getSize() die Größe des Fensters erfragen. Anschließend werden 2 diagonale Linien mit drawLine und ein Rechteck mit drawRect gezeichnet. Außerdem wird ein roter gefüllter Kreis in der Nähe des Mittelpunktes gezeichnet. Die Klasse zum Zeichnen des Fensters wird im Hauptprogramm aufgerufen und aktiviert. Vielleicht ist auch aufgefallen, das die Linien über das ganze Fenster gemalt sind. Diesen Missstand wollen wir in den nächsten Programmen beheben. Ansonsten regiert das Programm schon ganz gut auf die Veränderung der Fenstergröße. Alle Elemente passen sich automatisch an. Programm P21.java : Graphische Oberfläche mit Zeichenfläche, Label und Knopf /* JAFF = Java fuer Foerster Ereignis orientierte Programmierung: Grafikfenster Zeichnen auf eine Leinwand, Überschrift und ein Knopf */ import java.awt.*; class ZFlaeche extends Canvas { public void paint(Graphics g) { g.drawString("Waldsimulator",100,100); Dimension d=getSize(); Jaff : Java für Förster 01.12.03 J. Nagel Seite 39 von 48 int w=d.width, h=d.height; //Zeichnen zweier Linien g.drawLine(0,0,w-1,h-1); g.drawLine(0,h-1,w-1,0); // Zeichnen eines Rechtecks g.drawRect(0,0,w-1,h-1); // Farbe einstellen g.setColor(Color.red); // Einen gefüllten Kreis in rot zeichnen g.fillOval(w/2,h/2,30,30); } } public class p21 { public static void main (String args[]) { Frame F=new GFenster(); F.setSize(500,500); // Ein Label als Überschrift F.add("North", new Label("Test Grafik")); // Hier wird das Canvas in die Mitte des Fensters gesetzt F.add("Center",new ZFlaeche()); // einen Knopf zum beenden unter die Grafik F.add("South", new Button("beenden")); F.setVisible(true); } } Das Programm P21 zeigt, wie wir durch die Verwendung einer Zeichenfläche unsere Grafik auf einen Teil des Fensters beschränken können. Gleichzeitig wurde das Fenster mit einem Label und ein Knopf versehen. Der Knopf hat zwar noch keine Funktion, aber diese werden wir ihm noch verleihen. Mit den Angaben North, South, East, West und Center kann man die Elemente auf dem Fenster positionieren. Möchte man zwei Knöpfe z.B. unten anbringen, so sollte man ein Panel verwenden und auf dieses zwei Knöpfe positionieren. Aufwendigere Designs erzielt man über Tabellen, dazu verwendet man das GridLayout. Dies ist ähnlich wie bei HTML-Seiten. Der Verzicht auf eine direkte Positionierung der Elemente hat aber den Vorteil, daß die Programme auf Rechnern mit ganz unterschiedlicher Auflösung und Betriebssystemen trotzdem ansprechend aussehen. Bei der Programmierung neigt man häufig dazu, ein spezielles Bildschirmdesign zu entwerfen, was nur auf den eigenen Bildschirm zugeschnitten ist. Programm p22.java : GUI mit Gridlayout /* JAFF = Java fuer Foerster Ereignis orientierte Programmierung: Grafikfenster Zeichnen auf eine Leinwand, Überschrift und ein Knopf */ import java.awt.*; class ZFlaeche extends Canvas { public void paint(Graphics g) { g.drawString("Waldsimulator",100,100); Dimension d=getSize(); int w=d.width, h=d.height; //Zeichnen zweier Linien Jaff : Java für Förster 01.12.03 J. Nagel Seite 40 von 48 g.drawLine(0,0,w-1,h-1); g.drawLine(0,h-1,w-1,0); // Zeichnen eines Rechtecks g.drawRect(0,0,w-1,h-1); // Farbe einstellen g.setColor(Color.red); // Einen gefüllten Kreis in rot zeichnen g.fillOval(w/2,h/2,30,30); } } public class p22 { public static void main (String args[]) { Frame F=new GFenster(); //Die grafischen Elemente werden tabellenartig angeordnet F.setLayout(new GridLayout(0,2)); // F.setSize(500,500); // Ein Label als Überschrift F.add( new Label("Test Grafik")); // Hier wird das Canvas in die Mitte des Fensters gesetzt F.add(new ZFlaeche()); // einen Knopf zum beenden unter die Grafik F.add( new Button("beenden")); F.add( new Button("Knopf 2")); // mit pack wird die Größe des Fensters abgestimmt F.pack(); F.setVisible(true); } } Variante p22 zeigt die Verwendung des GridLayouts, welche für diese Anwendung sicherlich nicht am geeignesten ist, aber die Funktion GridLayout verdeutlicht. Mit dem Methode F.pack(); läßt sich die Fenstergröße auf die minimal nötige Größe für das Programm bestimmen. Programm p23.java : GUI mit Knopf- Aktionen. /* JAFF = Java fuer Foerster Ereignis orientierte Programmierung: Grafikfenster Schließen des Programms über einen Knopf */ import java.awt.*; import java.awt.event.*; class ZFlaeche extends Canvas { public void paint(Graphics g) { g.drawString("Waldsimulator",100,100); Dimension d=getSize(); int w=d.width, h=d.height; //Zeichnen zweier Linien g.drawLine(0,0,w-1,h-1); g.drawLine(0,h-1,w-1,0); // Zeichnen eines Rechtecks g.drawRect(0,0,w-1,h-1); // Farbe einstellen g.setColor(Color.red); Jaff : Java für Förster 01.12.03 J. Nagel Seite 41 von 48 // Einen gefüllten Kreis in rot zeichnen g.fillOval(w/2,h/2,30,30); } } class schliessen implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } public class p23 { public static void main (String args[]) { Frame F=new GFenster(); F.setSize(500,500); // Ein Label als Überschrift F.add("North", new Label("Test Grafik")); // Hier wird das Canvas in die Mitte des Fensters gesetzt F.add("Center",new ZFlaeche()); // einen Knopf zum beenden unter die Grafik Button b=new Button("beenden"); b.addActionListener(new schliessen()); F.add("South", b); F.setVisible(true); } } In Programm p23 wird nun endlich gezeigt, wie wir das Programm sauber wieder schließen können. Dazu erzeugen wir uns zunächst die Variable b der Klasse Button. Diesem Knopf wird nun mit b.addActionListener(new schliessen()) ein sogenannter ActionListener hinzugefügt, der als Argument die Klasse mit der gewünschten Aktion enthält. In dieser Klasse schliessen() stehen die nötigen Anweisungen, im speziellen Fall der Befehl System.exit(0);, der ein Programmende bewirkt. Bei der Klassendeklaration ist es nötig, daß wir das Element implements ActionListener hinzufügen. Als letzte Übung wollen wir nun das Programm derartig schreiben, daß der rote Kreis über Knopf gesteuert anfängt zu wachsen. Hierzu ist es nötig das Programm ein wenig zu verändern. Programm p24.java : GUI mit Wachstum import java.awt.*; import java.awt.event.*; class ZFlaeche extends Canvas implements MouseListener { private int x=-100,y=-100; public ZFlaeche() { addMouseListener(this); } // Methode die die Grafik zeichnet public void paint (Graphics g) Jaff : Java für Förster 01.12.03 { J. Nagel g.drawRect(x-10,y-10,20,20); g.drawString("Waldsimulator",100,100); Dimension d=getSize(); int w=d.width, h=d.height; //Zeichnen zweier Linien g.drawLine(0,0,w-1,h-1); g.drawLine(0,h-1,w-1,0); // Zeichnen eines Rechtecks g.drawRect(0,0,w-1,h-1); // Farbe einstellen g.setColor(Color.red); // Einen gefüllten Kreis in rot zeichnen Kreis k= new Kreis(); g.fillOval(w/2,h/2,k.hole(),k.hole()); } // methode die die Maus beobachtet public void mousePressed (MouseEvent e) { x=e.getX(); y=e.getY(); repaint(); } //leere Methoden public void mouseReleased (MouseEvent e) { } public void mouseEntered (MouseEvent e) { } public void mouseExited (MouseEvent e) { } public void mouseClicked (MouseEvent e) { } //neu Zeichnen public void neuzeichnen() { repaint(); } } // Klasse zum Schließen des Fensters class schliessen implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } //Klasse Kreis class Kreis { static int radius = 20; void wachsen() { radius=radius + 10; } int hole() { return radius; } } // Klasse für das Fenster class FensterFrame extends Frame implements ActionListener { ZFlaeche zf = new ZFlaeche(); public FensterFrame () { super("Modell"); setSize(500,500); setVisible(true); // Ein Label als Überschrift Seite 42 von 48 Jaff : Java für Förster 01.12.03 J. Nagel Seite 43 von 48 add("North", new Label("Test Grafik")); // Hier wird das Canvas in die Mitte des Fensters gesetzt add("Center",zf); Panel Psued = new Panel(); // Knopf zum Wachsen Button b1=new Button("Wachsen"); Psued.add("South", b1); b1.addActionListener(this); // einen Knopf zum beenden unter die Grafik Button b2=new Button("beenden"); b2.addActionListener(new schliessen()); Psued.add("South", b2); // Panel für die unteren Knöpfe add("South",Psued); // F.repaint(); setVisible(true); addWindowListener( new WindowAdapter () { public void windowClosing (WindowEvent e) { dispose(); System.exit(0); } } ); } public void actionPerformed (ActionEvent e) { Kreis k = new Kreis(); k.wachsen(); zf.neuzeichnen(); // Rabiater Schluss } } public class p24 { public static void main (String args[]) { new FensterFrame(); } } In der Klasse p24 wird die Klasse aufgerufen, die das Arbeitsfenster definiert. Dieses Arbeitsfenster, im Beispiel FensterFrame genannt, ist eine Erweiterung der Klasse Frame und implementiert einen ActionListener. Zur Klasse Fensterframe werden die Elemente des Arbeitsfenster, eine Zeichenfläche, eine Überschrift und zwei Knöpfe wie in den vorherigen Beispielen hinzugefügt. Die Knöpfe werden beide mit einem ActionListener versehen. Über den ersten Knopf wird die Klasse Schließen aufgerufen und ausgeführt. Der andere Knopf aktiviert die Methode actionPerformed, die wiederum die Zuwachsmethode des Kreises aufruft und dafür sorgt, daß die Methode neuzeichnen() der Klasse Zeichenflächen aufgerufen wird. Am Ende der Klasse FensterFrame wird noch ein Windowslistener hinzugefügt, der es ermöglicht, daß man das Fenster und Programm auch über den Knopf zum Schließen des Fensters beenden kann. – Die Klasse Kreis definiert den Radius, der zu Anfang auf den Startwert von 20 gesetzt wird. Die Klasse verfügt über die Methoden wachsen() und hole() zum Abfragen des Durchmessers. Die Jaff : Java für Förster 01.12.03 J. Nagel Seite 44 von 48 Klasse Zflaeche implemiert einen MausListener mit dem wir Mausbewegungen auf der Zeichenfläche abfragen können. Die Zeichnung wird mit der Methode neuzeichnen() ausgeführt. Startet man das Programm und drückt auf den Knopf wachsen, so wird die Grafik mit der neuen Kreisgröße gezeichnet. In den vorherigen 24 kleinen Programmen, haben wir die wichtigsten Elemente der Programmierung kennengelernt. Mit diesen wenigen Elementen, kann man fast alle wichtigen Probleme lösen. Im folgenden Projekt Projekt1 wollen wir nun das zuvor besprochene verwenden, um ein kleines und einfaches interaktives Wachstumsmodell zu erstellen. Dokumentation mit javadoc Die Entwicklungsumgebung von Java verfügt über ein einfaches Werkzeug mit man mehr oder weniger automatisch sein Java Programm oder seine Java Klassen dokumentieren kann. Im Stil der Java-Dokumentation werden durch den Aufruf von C:\jaff\projekt1\javadoc –private *.java unsere gesamten erstellten Klassen dokumentiert. Man kann die Dokumentation erheblich verbessern, wenn man vor die Methoden und die Variablen der Klasse jeweils einen Kommentar einfügt. Der Kommentar wird von Javadoc berücksichtigt, wenn er durch /** und */ abgegrenzt wird. Erzeugen Sie die Dokumentation und sehen Sie sich das Ergebnis an, in dem Sie mit dem Browser die Datei c:\jaff\projekt1\index.html aufrufen. Weitergabe Falls Sie ein Programm weitergeben wollen, müssen Sie zunächst entscheiden, wie Sie es weitergeben wollen. Dazu ist grundsätzlich die Frage zu klären, soll derjenige den gesamten oder Teile des Scource-Code erhalten und später in der Lage sein Änderungen selber zu machen, oder möchten wir ihm das Programm nur in der Form geben, in der es zur Zeit exisiert und lassen keinen Einblick in die Programmierung zu. Die Antwort zu dieser Frage hängt ganz von den persönlichen Verhältnissen ab. Falls man von seinen Programmen leben möchte, wird man den Scource-Code in der Regel nicht oder nur gegen die Bezahlung einer den Programmieraufwand entsprechenden Summe mitliefern. Hat man den Programmcode erst einmal aus der Hand gegeben, so können die Benutzer Änderungen machen und man hat keine Kontrolle mehr über das Programm, z.B. ob das von einem selbst getestete Programme auf Grund von Veränderungen mit einem Mal zu neuen Fehlern führt. Wie immer Sie sich nun entscheiden, ist letztlich Ihre Sache. Will man dem Benutzer auch den Source Code komplett oder teilweise zur Verfügung stellen, dann braucht man nur das Verzeichnis mit allen *.java und *.class Dateien dem Benutzer weitergeben. Er kann sich von der Internetseite der Firma SUN entweder die Java Entwicklungsumgebung oder falls er das Programm wirklich nicht verändern möchte die JavaRuntime Umgebung herunterladen und das Programm verwenden. Im Fall, daß der Benutzer keinen Einblick in die Programmierung bekommen sollte, gibt man nur die *.class Dateien weiter. Mit dem Befehl: Jaff : Java für Förster 01.12.03 J. Nagel Seite 45 von 48 C:\einVerzeichnis\>jar -cf wwmodel.jar *.class Kann man alle nötigen Class-Dateien in einer Datei zusammenfassen und komprimieren. In diesem Fall muß man dem Benutzer neben den Daten nur die Datei wwmodel.jar weitergeben. Testen Sie die Möglichkeit, in dem Sie die Datei wwModel.jar und die Daten Wald1.txt in ein eigenes Verzeichnis kopieren und dort mit dem Befehl aufrufen: C:\einVerzeichnis\>java –cp wwmodel.jar wwmodel Diese Zeile kann man mit dem Notepad-Editor auch in einer Datei mit der Endung *.bat speichern. Dann braucht der Benutzer unter Windows diese Datei nur doppelt anklicken. C:\einVerzeichnis\> wwmodel.bat Lösungen Aufgabe a4 Massentafel: public class a4 { public static void main (String args[]) { double vol =0.0; int bhdvon=15; int bhdbis=20; // Massentafel System.out.println(" M a s s e n t a f e l "); System.out.println(" Hoehe "); System.out.print("BHD "); for (int j=12;j<18;j=j+2) {System.out.print(" "+j+" ");} System.out.println(); for (int i=bhdvon;i<bhdbis;i=i+1) { System.out.print(" "+i+" "); for (int j=18;j<24;j=j+2) { vol=0.4786-(1.0111/j)+(2.041/i)-(203.12/(i*j*j)); vol=Math.PI*(i/200.0)*(i/200.0)*j*vol; vol=Math.round(vol*100.0)/100.0; System.out.print(" "+vol+" "); } System.out.println(); } } } Aufgabe a5 : Wachstum der Winterlinde public class a5 { public static void main (String args[]) { int alter = 5; //setzen des Startalters double hoehe =0.20 ; //setzen der Starthoehe double ihmax =0.0 ; //speichern des max. Zuwachses int alterihmax =0 ; // Alter des max. Hoehenzuwachses Jaff : Java für Förster 01.12.03 J. Nagel Seite 46 von 48 double ih = 0.0; // Variable für den Hoehenzuwachs for (int i=5;i<=100;i++) { ih=(0.495586*hoehe)/(Math.pow(alter,1.011263))*Math.log(96.173358/hoehe); if (ih>ihmax) { ihmax=ih; //Hoehenzuwachs umspeichern alterihmax=i; //Alter merken } if (i==100) System.out.println("Hoehe im Alter 100:"+hoehe); hoehe = hoehe+ih; //Hoehe um den Hoehenzuwachs erhöhen alter = alter+1; } System.out.println("Maximale Hoehenzuwachs: "+ihmax+" im Alter: "+alterihmax); } } Aufgabe a6 : Sortieren Dg und D100 // Aufgabe: Schreiben Sie ein Programm, mit dem Sie 20 zufällige BHD-Werte sortieren können. // Berechnen Sie dann den D100 und den Dg. Es gilt, dass sich die 20 Bäume auf eine Fläche // von 0.1 ha beziehen. Hinweis: Die Quadratwurzel einer Zahl erhalten Sie mit der Methode // sqrt der Klasse Math ( 2.0=Math.sqrt(4.0) ). Mehr zu der Klasse Math ist später im Text // beschrieben public class a6 { public static void main (String args[]) { double d[]; // Definition der Array-Variable bhd d= new double[20]; // Bereitstellen des Array für 10 Variablen // 20 BHD generieren for (int i=0;i<20;i++) //Achtung der Array beginnt beim Index 0 d[i]=1.0+Math.random()*79.0; //zufälliger BHD zwischen 1.0 und ´80.0 // sortieren der 20 BHDs for (int i=0;i<19;i++) for (int j=i+1;j<20;j++) if (d[i]<d[j]) { double dmerk=d[i]; d[i]=d[j]; d[j]=dmerk; } // sortierte BHD zur Kontrolle ausschreiben for (int i=0;i<20;i++) System.out.println(i+" BHD: "+d[i]); // Kreisflächenmittelstamm berechnen double dg=0.0; for (int i=0;i<20;i++) dg=dg+Math.PI*(d[i]/200.0)*(d[i]/200.0); dg= 200.0*Math.sqrt(dg/(20.0*Math.PI)); System.out.println("Kreisflächenmittelstamm: "+dg); // Kreisflächenmittelstamm der 100 stärksten, hier 10 stärkste Bäume double d100=0.0; for (int i=0;i<10;i++) d100=d100+Math.PI*(d[i]/200.0)*(d[i]/200.0); d100= 200.0*Math.sqrt(d100/(10.0*Math.PI)); System.out.println("D100 : "+d100); Jaff : Java für Förster 01.12.03 } } J. Nagel Seite 47 von 48 Jaff : Java für Förster 01.12.03 J. Nagel Seite 48 von 48 Index abstract 18 ActionListener 35 API 30 Arrays 16 AWT 30 Basisklasse 18 Block 9, 12 break 15 case 15 class 18 Classpath 6 Compiler 5 continue 15 Datentypen 11 do ... while -Schleife 15 Dokumentationskommtentar 9 ELSE 12 extends 20 Extension 6 Feldvariablen 16 final 18 for-Schleife 14 Frame 32 GUI 30 Hüllklassen 23 IF 12 import 25 Import 30 Instanzen 17 int 11 Integer 10 Interfaces 18 Interpreter 5 Klassen 17 Konstruktor 18 Lesen 25 Maschinensprache 5 Modifizier 18 Objekte 17 Operatoren 10 OutputStream 27 path 6 public 18 Schleifen 13 Schreiben 25 Substrings 26 switch 15 umwandeln 23 Vererbung 20 Vergleichsoperatoren 12 void 9 while-Schleife 13 Zeilenkommentar 9