Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 Aufgabe 1: Collections: ZockerBank Herzlichen Glückwunsch! Nachdem Sie den Java-Kurs fast erfolgreich abgeschlossen haben, winkt Ihnen bereits ein Auftrag der Bank „Geizkragen und Zocker Gesellschaft ohne Haftung“. Erstellen Sie ein kleines Programm zur ZockerBank-Verwaltung. Dabei haben Sie die Gelegenheit, Ihre Kenntnisse zu Collections zu vertiefen und andere bisher behandelte Themen zu wiederholen. a) Erstellen Sie eine Klasse ZockerKonto. • Ein ZockerKonto besitzt eine Nummer und einen Kontostand und einen Inhaber. • Der Konstruktor bekommt einen Anfangsbetrag und den Namen des KontoInhabers übergeben. Die innerhalb der Bank eindeutige Kontonummer wird von der Bank vergeben. Jedes erzeugte ZockerKonto soll automatisch auch der Bank (siehe unten) bekannt sein, sodass diese alle Ihre Konten kennt. • Ferner besitzt ein Konto eine Methode kontostandAendern zum Einzahlen eines Betrages bzw. zum Auszahlen (Betrag < 0). Dabei darf das Konto nicht überzogen werden und im Falle der versuchten Kontoüberziehung eine KontoUeberziehungException ausgelöst werden. • Überlegen Sie selbst, welche Methoden Sie ggf. noch darüber hinaus benötigen. b) Erstellen Sie nun eine Klasse ZockerBank. • Die ZockerBank–Klasse muss geeignet seine Konten verwalten. • Die Klasse soll geeignete get-Methoden bieten, um alle vorhandenen Konten abfragen zu können. • Eine ZockerBank besitzt eine Methode kontoHinzufuegen, um ein neues Konto hinzuzufügen. • Hinweise: o Die ZockerBank–Klasse ist nur für die Verwaltung der Bank „Geizkragen und Zocker Ges. ohne Haftung“ gedacht und nicht für andere Banken. o Überlegen Sie sich, in welcher Datenstruktur Sie Ihre Daten abspeichern wollen – Java bietet hier eine reiche Sammlung vordefinierter Datenstrukturen an, aus denen Sie lediglich geeignet auswählen müssen. S. 1 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 c) Erstellen Sie nun eine Klasse TestZockerBank mit einer geeigneten Methode zum Testen. • Erstellen Sie einige Test-Konten und geben Sie die Bank bzw. deren Konten auf dem Bildschirm aus. • Versuchen Sie dann einige Kontoänderungen, auch mit eventueller Überziehung. Geben Sie danach die geänderten Konten (mit den geänderten Kontoständen) aus. Zusatz-Aufgabe 2: Ein-/Ausgabe in Dateien: ZockerBank a) Erweitern Sie Ihre Klasse ZockerBank aus der vorherigen Aufgabe um Methoden saveToFile und readFromFile, welche alle Konten in eine Datei schreiben bzw. aus dieser wieder einlesen. b) Testen Sie diese Methoden, indem Sie die Bank in eine Datei schreiben, wieder einlesen, und dann den aktuellen „Zustand“ der Bank auf dem Bildschirm ausgeben. Aufgabe 3: Kommunikation mit Sockets Erstellen Sie zwei kleine Test-Klassen zur Kommunikation über Sockets. a) Erstellen Sie eine Klasse test.socket.Server • Beim Start des Servers soll dieser auf einem festgelegten Port (z.B. 5000) als SocketServer lauschen, d.h. eingehende Anfragen von Clients akzeptieren. • Erzeugen Sie zur Bearbeitung der Client-Anfragen jeweils einen eigenen Thread. Dieser soll alle eingehenden Text-Nachrichten auf dem Client-Socket auf dem Bildschirm ausgeben und (als Echo) an den Client-Socket zurückschicken (siehe unten). Übergeben Sie dazu im Konstruktor den Socket für die Verbindung mit dem Client. • Öffnen Sie die Socket-Verbindung zum remote Partner (d.h. erzeugen Sie einen BufferedReader auf dem Socket-EingabeStrom und einen PrintWriter auf dem Socket-Ausgabestrom.). • Lesen Sie dann aus dem Eingabe-Socket (dem obigen BufferedReader) zeilenweise die jeweiligen Nachrichten ein. S. 2 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik • Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 Senden Sie auf dem PrintWriter-Objekt ihrem jeweiligen Kommunikationspartner eine Kopie der erhaltenen Nachricht. b) Erstellen Sie analog eine Klasse test.socket.Client. • Lesen Sie von der Konsole (Tastatur) den Hostnamen bzw. die IP-Adresse des Servers (z.B. localhost oder 192.168.22.<PC-Nr>) ein. Öffnen Sie dazu einen BufferedReader auf einem InputStreamReader, der mit dem Eingabestrom System.in verknüpft ist. Hinweis: Sie können Ihr Programm zunächst lokal auf Ihrem Rechner (localhost) testen, anschließend können Sie sich mit einem anderen Rechner verbinden. Dessen IP-Adresse lässt sich mittels ipconfig ermitteln. • Bauen Sie dann eine Socket-Verbindung zu diesem Server-Rechner und der Portnummer des Servers auf. • Senden Sie eine oder mehrere Text-Nachrichten an den Server, und geben Sie jeweils die vom Server empfangenen Daten auf dem Bildschirm aus. Testen Sie die Kommunikation, indem Sie zunächst den Server starten, und anschließend den Client. Aufgabe 4: Wiederholung Was ist in folgendem Code (vermutlich) fehlerhaft und wie könnten Sie es korrigieren? a) Klasse Strange1 class Strange1 { public static void main(String args) { JFrame frame = new JFrame("Hallo"); JButton button = new JButton("Welt"); button.addActionListener(this); button.add(frame); } } S. 3 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 b) Klasse Strange2 class Strange2 extends Cloneable { public static void main(String args) { Thread t = new Thread(Strange1); t.run(); } private void start() { System.in.println("in start"); Runnable r = new Runnable(); r.start(); } } Zusatz-Aufgabe 5: Tic Tac Toe Vervollständigen Sie das Spiel Tic Tac Toe. Zusatz-Aufgabe 6: Kommunikation mit Sockets: TicTacToe Erweitern Sie das Spiel TicTacToe derart, dass zwei Spieler gegeneinander spielen können. Eine lauffähige stand-alone Version (für einen Spieler) liegt als Vorlage auf der Webseite. a) Erstellen Sie eine Klasse Server. • Beim Start des Servers soll dieser auf einem festgelegten Port (z.B. 5000) als SocketServer lauschen, d.h. eingehende Anfragen von Clients akzeptieren. • Erzeugen Sie zur Bearbeitung der Client-Anfragen jeweils einen eigenen Thread: Erzeugen Sie dort ein neues TicTacToe-Spiel (d.h. ein Objekt der Klasse Tic), wobei Sie den Client-Socket übergeben. In Tic.run() wird wie gehabt das Spielfenster mit den Panels, Buttons und Listener-Methoden initialisiert. (siehe Vorlage). b) Erstellen Sie analog eine Klasse Client. • Lesen Sie von der Konsole (Tastatur) den Hostnamen des Servers (z.B. localhost oder PC31202) ein. S. 4 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 • Bauen Sie dann eine Socket-Verbindung zu diesem Server-Rechner und der Portnummer des Servers auf. • Erzeugen Sie ein neues TicTacToe-Spiel (d.h. ein Objekt der Klasse TicTacToe), wobei Sie den Client-Socket übergeben. d) Erweitern Sie schließlich die Klasse TicTacToe wie folgt: • Übergeben Sie im Konstruktor einen Socket für die Verbindung mit dem remote Partner sowie den eigenen Spieler (Kreuz oder Kreis?). • Öffnen Sie die Socket-Verbindung zum remote Partner (d.h. erzeugen Sie einen BufferedReader auf dem Socket-EingabeStrom und einen PrintWriter auf dem Socket-Ausgabestrom.). • Lesen Sie dann aus dem Eingabe-Socket (dem obigen BufferedReader) zeilenweise die jeweiligen Kommandos ein. Sie können zur Auswertung die Methode parseGameCommand aus Tic verwenden. Hinweis: Die Methode parseGameCommand muss zu Ihren gesendeten Kommandos (siehe unten) passend sein! • Senden Sie auf dem PrintWriter-Objekt ihren jeweiligen Kommunikationspartner alle Spielzüge, die Sie in der GUI ausgewählt haben (d.h. erweitern Sie die jeweiligen mit TODO markierten Code-Stellen): o „newGame“ beim Start eines neuen Spiels o „endGame“ beim Ende des Spiels o „setzeFeld/<feldX>/<feldY>“ nach dem Auswählen eines Feldes mit der Maus. Testen Sie die Kommunikation, indem Sie zunächst den Server starten, und anschließend den Client. Spielen Sie das Spiel zunächst lokal auf einem Rechner, dann mit Partner im Netz. S. 5 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 Zusatz-Aufgabe 7: Kommunikation mit RMI: TicTacToe Nicht ausgelastet? Verwenden Sie statt Sockets direkte RMI-Aufrufe zur Kommunikation im Spiel TicTacToe. Zusatz-Aufgabe 8: Pong Nicht ausgelastet? Bauen Sie die Bewegung von Bällen aus Übung 9 zum Spiel Pong aus: • Erzeugen Sie wie gewohnt ein Panel und ein JFrame. • Zeigen Sie zunächst zwei Schläger (Objekte der Klasse Paddle) auf einen Panel. Lassen Sie diese Schläger sich aufwärts und abwärts bewegen. Reagieren Sie dazu auf jeweils eine Taste für den linken bzw. rechten Schläger. Drücken der jeweiligen Taste (keyPressed) bewegt den zugehörigen Schläger nach oben, beim Loslassen der Taste (keyReleased) „fällt“ der Schläger nach unten bewegt ihn nach unten. Beachten Sie, dass die Schläger (Paddle-Objekte) innerhalb des Panels bleiben müssen, d.h. nicht über den oberen bzw. unteren Rand hinausragen dürfen. • Sofern noch kein Ball im Spiel ist, kann der jeweils aktive Spieler (d.h. derjenige mit dem letzten Ballgewinn) durch Drücken (keyTyped) einer weiteren Taste (z.B. der Leertaste) einen Ball von der aktuellen Position des eigenen Schlägers in Richtung der gegnerischen Seite starten. Der Ball prallt oben und unten an Rand jeweils ab. Beim Überschreiten des linken bzw. rechten Spielfeldrandes erhält der gegenüberliegende Gegner einen Punkt, und der Ball ist aus dem Spiel. Durch Schlag (= Berührung) des Balles mit dem Schläger kann versucht werden, dies zu verhindern und dadurch den Ball in die entgegengesetzte Richtung (hin zum Gegner) zu spielen. S. 6 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 Zusatz-Aufgabe 9 (für Java-Experten): Java-Rätsel – Ein-/Ausgabeströme a) Die folgende Methode kopiert eine Datei (von src nach dest). Dabei wurde darauf geachtet, dass jeder erzeugte Ein-/Ausgabestrom auch wieder geschlossen wird, selbst beim Auftreten von Ein-/Ausgabefehlern. Leider werden nicht immer alle Ströme geschlossen. Warum nicht, und wie könnte man die Methode korrigieren? static void copy(String src, String dest) throws IOException { InputStream in = null; OutputStream out = null; try { in = new FileInputStream(src); out = new FileOutputStream(dest); byte[] buf = new byte[1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { if (in != null) in.close(); if (out != null) out.close(); } } b) Das folgende Programm zeigt einige Eigenschaften der Java-Klassen Date und Calendar. Was gibt das Programm aus? import java.util.Calendar; import java.util.Date; public class DatingGame { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); cal.set(1999, 12, 31); // Jahr, Monat, Tag System.out.print(cal.get(Calendar.YEAR) + " "); Date d = cal.getTime(); System.out.println(d.getDay()); } } S. 7 / 8 Hochschule Niederrhein Fachbereich 03 Bachelor Informatik Grundlagen der Java Programmierung SS 2015 Prof. Dr. Nitsche Übung 10 c) Ein Name kann für mehrere Klassen in verschiedenen Paketen verwendet werden. Dieses Programm untersucht was passiert, wenn wir einen Klassennamen der JavaBibliothek wiederverwenden. Was gibt das Programm aus? (Auch wenn Sie normalerweise solche Programme kaum sehen werden – versuchen Sie es zu verstehen.) public class StringTest { public static void main(String[] args) { String s = new String("Hallo world"); System.out.println(s); } } class String { private final java.lang.String s; public String(java.lang.String s) { this.s = s; } public java.lang.String toString() { return s; } } S. 8 / 8