Nebenläufigkeit Inhaltsverzeichnis Hypertext-Version Literatur © APSIS GmbH

13. Standardpakete

Seite 279

13.1. Das Fensterpaket – java.awt

Seite 280

13.1.1. Fensterkomponenten

Seite 281

import java.awt.*; // (13.1)
public class AWTdemo extends Frame {
	public AWTdemo() {
		super("AWT Demo"); // eigene Titelleiste
		... // wird später ergänzt
	}
}
	static AWTdemo grundfenster; // Referenz fürs Hauptprogramm
	public static void main (String[] args) {
		grundfenster = new AWTdemo();
		grundfenster.fensterAufbauen();
	}
public void fensterAufbauen() {
	Label beschriftung = new Label ("Popup-Menü auf Knopfdruck"); // ¬
	grundfenster.add(beschriftung); // ¬
	Button knopf = new Button("Popper"); // ¬
	knopf.setForeground(Color.black);
	knopf.setBackground(Color.yellow);
	grundfenster.add(knopf); // ¬
	fensterMenue = new PopupMenu(); // ¬
	MenuItem m1 = new MenuItem("maximieren");
	MenuItem m2 = new MenuItem("minimieren");
	MenuItem m3 = new MenuItem("schließen");
	MenuItem m4 = new MenuItem("drucken");
	fensterMenue.add(m1);
	fensterMenue.add(m2);
	fensterMenue.add(m3);
	fensterMenue.add(m4);
	grundfenster.add(fensterMenue); // ¬
	grundfenster.pack(); // die Komponenten anordnen
	grundfenster.show(); // das Fenster sichtbar machen
}

13.1.2. Anordnung der Komponenten

Seite 282

grundfenster.add(BorderLayout.NORTH, beschriftung); // Label
grundfenster.add(BorderLayout.SOUTH, knopf); // Button
grundfenster.add(fensterMenue); // PopupMenu
grundfenster.setLayout(new FlowLayout());
Panel knopffeld = new Panel();
knopffeld.setLayout(new BorderLayout());
Button maxknopf = new Button("Maximieren");
Button minknopf = new Button("Minimieren");
Button schliessknopf = new Button("Schließen");
Button druckknopf = new Button("Drucken");
knopffeld.add(BorderLayout.WEST, maxknopf);
knopffeld.add(BorderLayout.EAST, minknopf);
knopffeld.add(BorderLayout.NORTH, druckknopf);
knopffeld.add(BorderLayout.SOUTH, schliessknopf);

Übung 13.1: Testen Sie das Programm (13.1) auf Seite 281 mit verschiedenen Anordnungen. Fassen Sie auch die Beschriftung und den "Popper"-Knopf zu einem eigenen Panel zusammen.

13.1.3. Ereignisse und Reaktionen

Seite 283

knopf.addActionListener(new java.awt.event.ActionListener() { // (13.2)
		// anonymer Lauscher
	public void actionPerformed(ActionEvent e) {
		fensterMenue.show(grundfenster, 200, 75); // Popup-Menü aufklappen
	}
});
Ereignistyp Von processEvent gerufene Methode
ActionEvent ProcessActionEvent
MouseEvent ProcessMouseEvent
ProcessMouseMotionEvent
FocusEvent ProcessFocusEvent
... ...

Abb. 13.1: Ereignisse

grundfenster.enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);
	// oder-Verknüpfung zweier Ereignistypmasken
public void processMouseEvent(MouseEvent e) {
	if (e.isPopupTrigger()) { // rechte Maustaste ¬
		fensterMenue.show(grundfenster, e.getX(), e.getY());
			// x- und y-Koordinaten der Mausposition
		e.consume(); // fertig bearbeitet, nicht weiterreichen
	}
}
public void processWindowEvent(WindowEvent e) {
	if (e.getID()== WindowEvent.WINDOW_CLOSING)
		System.exit(0);
}
public void fensterAufbauen() {
	Lauscher lauscher = new Lauscher(); // Lauscherobjekt(e) erzeugen
	Panel knopffeld = new Panel(); // Knopffeld
	... // vier Knöpfe erzeugen
	// Standard-Ereignisbehandlung mit Lauscherobjekt(en)
	maxknopf.addActionListener(lauscher); // der Universallauscher
	minknopf.addActionListener(lauscher);
	schliessknopf.addActionListener(lauscher);
	druckknopf.addActionListener(lauscher);
	grundfenster.add(knopffeld);
	// Popup-Menü
	fensterMenue = new PopupMenu("fenster");
	... // vier Menüfelder erzeugen
	// Standard-Ereignisbehandlung, gleiches Lauscherobjekt wie oben:
	m1.addActionListener(lauscher); // der Universallauscher
	m2.addActionListener(lauscher);
	m3.addActionListener(lauscher);
	m4.addActionListener(lauscher);
	grundfenster.add(fensterMenue);
	...
}
class Lauscher implements ActionListener {
	public void actionPerformed(ActionEvent e) {
		String kommando = e.getActionCommand();
		if (kommando.equalsIgnoreCase("Maximieren")) // "maximieren" gleich "Maximieren"
			grundfenster.maximieren();
		else if (kommando.equalsIgnoreCase("Minimieren"))
			grundfenster.minimieren();
		else if (kommando.equalsIgnoreCase("Drucken"))	
			grundfenster.bildschirmabzug();
		else if (kommando.equalsIgnoreCase("Schließen"))
			grundfenster.schliessen();
	}
}

Übung 13.2: Realisieren Sie das "saubere" objektorientierte Lauscherkonzept für das Programm (13.2) auf Seite 283: Implementieren Sie für jedes der o.g. Ereignisse einen eigenen Lauscher; die Abfrage auf die Art des Kommandos entfällt dann. Beachten Sie: Nur vier verschiedene Lauscher müssen erzeugt werden, da den unterschiedlichen Maximierungsereignissen dasselbe Lauscherobjekt zugeordnet werden kann, ebenso für Minimierung, usw.

Übung 13.3: Lösen Sie nun im Programm (13.2) auf Seite 283 die Aktionen mit Hilfe des vereinfachten Ereignismodells (d.h. über processActionEvent) aus.

13.1.4. Grafik

Seite 285

public void paint(Graphics grafik) { // (13.3)
	grafik.setFont(new Font("Helvetica", Font.BOLD, 30));
	grafik.setColor(Color.cyan.darker());
	grafik.drawString("Man kann im Grundfenster malen", 40, 40);
	// y groß genug wählen, damit die Schrift nicht oben aus dem Fenster verschwindet
}
// Zeichenfläche definieren und paint-Methode überschreiben:
class Atelier extends Canvas {
	public void paint(Graphics grafik) {
		grafik.setFont(new Font("Helvetica", Font.BOLD, 20));
		grafik.setColor(Color.blue);
		grafik.drawString("Man kann in der Zeichenfläche malen", 5, 25);
	}
}
// Zeichenfläche anlegen, formatieren und einbinden:
	zeichenflaeche = new Atelier();
	zeichenflaeche.setSize(500, 270);
	zeichenflaeche.setBackground(Color.lightGray); 
		// hebt die Zeichenfläche vom Grundfenster ab (zu Testzwecken)
	grundfenster.add(zeichenflaeche);
public void paint(Graphics grafik) {
	grafik.setFont(new Font("Helvetica", Font.BOLD, 30));
	grafik.drawString("Man kann im Grundfenster malen", 40, 430);
	zeichenflaeche.getGraphics().drawString(
		"... oder vom Grundfenster aus in die Zeichenflaeche hineinmalen", 25, 40);
	//...
}
try { // (13.4)
	Image meinBild = this.createImage((java.awt.image.ImageProducer)
		(new URL("file:/laufwerk:/[Pfad]/balloons.gif").getContent()));
			grafik.drawImage(meinBild, 5,40, this); // y groß genug, sonst unsichtbar ¬
}
catch (MalformedURLException e) { System.err.println(e); }
catch (IOException e) { System.err.println(e); }
try {
	Image meinBild = werkzeugkiste.getImage(
		new URL("file:/laufwerk:/[Pfad]/balloons.gif"));
	grafik.drawImage(meinBild, 5,40, this); // y groß genug wählen, sonst unsichtbar ¬
} catch (MalformedURLException e) { System.err.println(e); }

Übung 13.4: drawImage gibt es auch mit zwei weiteren int-Parametern, die die Wiedergabegröße des Bildes festlegen. Ein Bild lässt sich dadurch vergrößern, verkleinern, stauchen und strecken.

grafik.drawImage(bild, 5, 40, bild.getWidth(this), bild.getHeight(this), this);

ist gleich bedeutend mit der markierten Zeile des Programm (13.4) auf Seite 286. Suchen Sie sich ein schönes Bild (z.B. ein Foto) und versuchen Sie eine primitive Animation nach folgendem Muster:

final int BREITE = 100; // (13.5)
final int HOEHE = 100;
final int VERZOEGERUNG = 20000;
Image bild;
	...
public void init() { bild = ... }; // Image-Objekt erzeugen
public void paint(Graphics g) {
	for (int i = 0; i < 300; i++) {
		g.drawImage(bild, x, y, BREITE + i, HOEHE, this);
		Thread.sleep(VERZOEGERUNG); // kleine Pause
		g.clearRect(x, y, BREITE + i, HOEHE); // wieder löschen
	}
	repaint(); // und wieder von vorne
}

13.1.5. Bildschirmausdrucke

Seite 287

PrintJob ausdruck = this.getToolkit().getPrintJob(this, "Hardcopy", // (13.6)
	einstellungen);
if (ausdruck == null)
	return; // oder NullPointerException abfangen
private void bildschirmabzug(){
	java.util.Properties druckereinstellung = null; // Compiler fordert Initialisierung
	PrintJob ausdruck = werkzeugkiste.getPrintJob(this, "Hardcopy", druckereinstellung);
		// Benutzer setzt Druckereinstellungen im Dialog
	if (ausdruck == null) return; // Benutzer hat "Abbrechen" gewählt
	Graphics druckbild = ausdruck.getGraphics();
	this.print(druckbild); // this ist ein Frame-Objekt
	druckbild.dispose(); // Druckseite beenden und zum Drucker schicken
	ausdruck.end(); // Druckjob beenden
}

13.2. Quelltextinformation zur Laufzeit – java.lang.reflect

Seite 288

13.2.1. Methoden finden

Seite 288

public void iterator(final String rueckruf) { // (13.7)
	try {
		Knoten knoten = anfang;
		while (knoten != null) {
			Object ziel = knoten.wert; // der im Knoten gespeicherte Wert ist Zielobjekt
			Class klasse = ziel.getClass(); // Klasse des Zielobjekts ¬
			java.lang.reflect.Method methode = klasse.getMethod( // ¬
				rueckruf, new Class[0]); // gesuchte Methode
			methode.invoke(ziel, new Object[0]); // Aufruf der gefundenen Methode ¬
			knoten = knoten.vorwaerts; // zum nächsten Knoten gehen
		}
	} catch (Exception ausnahme) { System.err.println("Rueckruf: " + ausnahme); }
}
public Object invoke(Object obj, Object args[])
	throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
knoten.wert.getClass().getMethod(methode, new Class[0]).invoke(
	knoten.wert, new Object[0]);

13.2.2. Datenkomponenten finden

Seite 290

private String namenErmitteln() { // (13.8)
	return getClass().getFields()[knoten.pos].getName(); // ¬
}
private void setzen(final Knoten knoten) { // wie im Programm (9.15) versprochen
	Aufz ref = ersterAkt;
	for (int i = 0; i <= knoten.pos; i++) {
		ref.knoten.letzter = letzterAkt;
		ref = ref.knoten.naechster;
	}
}
public Field[] getFields() throws SecurityException; // ungeprüft
public static final Farbe BLAU = new Farbe();

Übung 13.5: Zeigen Sie, dass Reflexion polymorph ist: Rufen Sie eine Oberklassenmethode auf, die alle Felder und Methoden über getName anzeigt. Sie sind durch

public java.lang.reflect.Method[] getMethods() throws SecurityException

erhältlich. Sie erhalten auch die Unterklassenkomponenten. Sie können dabei auch beobachten, welche Komponenten von Object immer vererbt werden.

13.3. Datei-Ein/Ausgabe – java.io

Seite 291

import java.io.*; // (13.9)
public class Menuegenerator {
	private InputStream tastatur = System.in;
	private PrintStream konsole = System.out;
	private String tastaturEingabe(String dialogtext) throws IOException {
		konsole.println(dialogtext);
		StringBuffer puffer = new StringBuffer(); // zum Sammeln der Eingabezeichen
		int zeichen = tastatur.read(); // Byte-Eingaben als int-Werte
		while ((char)zeichen != '\n' && (char)zeichen != '\r' ) { // bis zum Zeilenende
			puffer.append((char) zeichen);
			zeichen = tastatur.read();
		}
		zeichen = tastatur.read();
		return puffer.toString();
	}
	...
import java.io.*;
public class Menuegenerator {
		...
	private FileWriter zieldatei; // wird mit der Ausgabedatei verbunden
	private PrintWriter ausgabe; // zur zeilenweisen Ausgabe in die Zieldatei
	private static void dateiUndKlassennamenSetzen() throws IOException {
		eingabe = tastaturEingabe ("Wie soll die Menüklasse heißen?");
		zieldatei = new FileOutputStream(eingabe + ".java");
		ausgabe = new PrintWriter(zieldatei, true);
		ausgabe.print("// Abstrakte Menüklasse " + eingabe + "\r\n");
		ausgabe.print("// erzeugt vom Menügenerator" + "\r\n" + "\r\n");
		ausgabe.print("import lehrbuch.Anim;" + "\r\n\r\n");
		ausgabe.print("abstract public class " + eingabe +
			" extends java.applet.Applet {");
		ausgabe.print("\r\n");	}
	...
}
import java.io.*;
public class Menuegenerator {
		...
	private FileReader schablone;
	private BufferedReader textbausteine; // zur zeilenweisen Eingabe
	static {
		try {
			schablone = new FileReader("MenueSchablone.txt");
		} catch (FileNotFoundException e) {
			System.err.println("Datei 'MenueSchablone.txt' nicht auffindbar" + e);
			System.exit(-1); // Programmabbruch mit Fehlercode -1
		}
		textbausteine = new BufferedReader(schablone);
	}
	private void kopierenBisXXX throws IOException {
		eingabe = textbausteine.readLine(); // zeilenweise Eingabe
		while (! eingabe.startsWith("XXX")) { // Endekriterium Textbaustein
			ausgabe.println(eingabe); // zeilenweise Ausgabe
			eingabe = textbausteine.readLine();
		}
	}
import java.io.*; // (13.10)
public class SeqDateiImpl implements SeqDatei {
	private boolean lesemodus;
	private Object aktuellesObjekt;
	private String dateiname;
	private ObjectInputStream eingabe; // ¬
	private ObjectOutputStream ausgabe; // ¬
	public SeqDateiImpl (String file) { // Konstruktor, setzt den Dateinamen
		dateiname = file;
	}
	public void neuBeschreiben() { // setzt Schreibmodus, setzt auf Anfang
		lesemodus = false;
		try {
			ausgabe = new ObjectOutputStream(new FileOutputStream(dateiname)); // ¬
		}
		catch (IOException e) { throw new DateiFehler(); }
	}
	public void zuruecksetzen() { // setzt Lesemodus + Anfang
		lesemodus = true;
		...
	}
	public void eintragen(final Object element) throws LesemodusFehler {
		if (lesemodus)
			throw new LesemodusFehler();
		else
			try {
				ausgabe.writeObject(element); // ¬
			} catch (IOException e) { throw new DateiFehler(); }
	}
	public void naechstesElement() throws SchreibmodusFehler, DateiendeAusn {
		if (!lesemodus)
			throw new SchreibmodusFehler();
		else
			try {
					aktuellesObjekt = eingabe.readObject(); // ¬
			} catch (EOFException eof) { throw new DateiendeAusn();
			} catch (Exception e) { throw new DateiFehler(); }
	}
	public Object aktuellesElement() throws SchreibmodusFehler, DateiendeAusn { ...
		return aktuellesObjekt;
	}
	...
}
class Getraenk implements java.io.Serializable { ... } // (13.11)
class Eimer implements java.io.Serializable { ... }
	...
Eimer eimer = new Eimer();
SeqDatei datei = new SeqDateiImpl("Eimer.dat");
datei.neuBeschreiben();
datei.eintragen(eimer);
	...

Übung 13.6: Schreiben Sie ohne Verwendung der Klasse SeqDateiImpl ein Programm, das menügesteuert Eimer, Kreise und Farben in einen polymorphen Datenbehälter einträgt und diesen als ganzes Objekt in eine Datei ausgibt. Schreiben Sie ein zweites Programm, das die Datei liest und den Inhalt des Datenbehälters anzeigt.

13.4. Java im Internet

Seite 294

13.4.1. Sicherheitskonzepte

Seite 295

13.4.2. Applets

Seite 295

public void init();
public void start();
public void stop();
public void paint(Graphics g); // geerbt von java.awt.Panel
<APPLET CODE="HalloWelt.class" WIDTH=450 HEIGHT=100 > </APPLET>
appletviewer Klasse.html

Abb. 13.2: Interpretieren mit appletviewer

getImage // zum Erzeugen von Bildobjekten aus .gif oder .jpeg-Dateien
getAudioClip // zum Erzeugen von Audioobjekten aus .au oder .wav
play // zum Abspielen von Audioobjekten
getCodeBase // ermittelt den Pfad bis zur aktuellen Applet-Datei
getDocumentBase // ermittelt den Pfad bis zur aktuellen HTML-Datei
getAppletContext // macht Kontextinformationen des Stöberers zugänglich

Übung 13.7: Suchen Sie sich eins ihrer Übungsprogramme heraus, das Sie mit av ausgeführt haben. Schreiben Sie nun die erforderliche Applet-Klausel selbst und rufen Sie das Programm direkt mit dem appletviewer auf.

13.4.3. Einbinden entfernter Applets in Netzseiten

Seite 297

<APPLET CODEBASE=http://www.tfh-berlin.de/~oo-plug/Java
	CODE=tfhLogo.class, WIDTH=200, HEIGHT=100>

13.4.4. Adressieren entfernter Objekte

Seite 297

Protokoll://Host[:Port]/Pfad/Dateiname[#interneReferenz]
http://www.tfh-berlin.de/~oo-plug/Java/tfhLogo.gif
public URL (String url) throws MalformedURLException;
public URL (String protocol, String host, String file) throws MalformedURLException;
public URL (String protocol, String host, int port, String file)
	throws MalformedURLException;
try { // (13.12)
	URL u1 = new URL ("http://tfh-berlin.de/~oo-plug/Java/tfhLogo.gif");
	URL u2 = new URL ("http", "tfh-berlin.de", "/~oo-plug/Java/tfhLogo.gif");
		// '/' vor Dateinamen erforderlich
	URL u3 = new URL ("http", "tfh-berlin.de", 80, "/~oo-plug/Java/tfhLogo.gif");
} catch (MalformedURLException ausnahme) { System.err.println(ausnahme); }
(u1.sameFile(u2) && u2.sameFile(u3)) == true;
public URL (URL url, String file) throws MalformedURLException;
URL u4 = new URL (u1, "tfhLogo.gif");
URL u5 = new URL (u1, "../Ada/adaLogo.gif");
URL u6 = new URL (getDocumentBase(), "beispiel.html");

13.4.5. Laden entfernter Textobjekte

Seite 298

public final InputStream openStream() throws IOException;
public URLConnection openConnection() throws IOException;
public final Object getContent() throws IOException;
URL u;
InputStream strom;
try {
	u = new URL("http://www.tfh-berlin.de/~oo-plug/Java/index.html");
	strom = u.openStream();
} catch (Exception ausnahme) { System.err.println(ausnahme); }
import java.net.*; // URL // (13.13)
import java.io.*; // DataInputStream
public class TextLaden {
	public static void main (String args[]) {
		URL url;
		String aktuelleZeile;
		DataInputStream lesestrom;
		if (args.length > 0) { // URL wird als Aufrufparameter erwartet
			System.out.println("Datei " + args[0] + ":\n");
			try {
				url = new URL(args[0]); // throws MalformedUrlException			
				lesestrom = new DataInputStream(url.openStream()); // throws IOException
				aktuelleZeile = lesestrom.readLine(); // throws IOException
				while (aktuelleZeile != null) {
					System.out.println(aktuelleZeile);
					aktuelleZeile = lesestrom.readLine(); // throws IOException
				}
			} catch (Exception ausnahme) { System.err.println(ausnahme); }
		}
	}
}

Übung 13.8: Probieren Sie das Programm TextLaden mit der Leitseite der TFH Berlin aus (allerdings vielleicht mit einer Zählschleife, die die Zahl der ausgegebenen Zeilen beschränkt!):

java TextLaden http://www.tfh-berlin.de

oder mit sich selbst:

java TextLaden file:/[Pfad]/TextLaden.java

13.4.6. Laden entfernter allgemeiner Objekte

Seite 299

try {
	URL url = new URL("http://www.tfh-berlin.de");
	ObjectInputStream objekt = new ObjectInputStream(url.openStream());
} catch (Exception ausnahme) { System.err.println(ausnahme); }
import java.net.*; // URL // (13.14)
import java.io.*; // DataInputStream
public class ObjektLaden {
	public static void main (String args[]) {
		URL url;
		String aktuelleZeile;
		DataInputStream lesestrom;
		if (args.length > 0) { // URL wird als Aufrufparameter erwartet
			try {
				url = new URL(args[0]); // throws MalformedUrlException
				Object obj = url.getContent();// throws ClassNotFoundException
				System.out.println("Es wurde ein " + obj.getClass().getName()
					+ "-Objekt erzeugt");
			} catch (Exception ausnahme) {System.err.println(ausnahme); }
		}
	}
}

Übung 13.9: Probieren Sie, ob HTML-Dateien auf ihrem System unterstützt werden: Rufen Sie das Programm (13.14) mit der Kommandozeile

java ObjektLaden url

auf und geben Sie als Parameter url Adressen von verschiedenen Dateitypen an. Mit der Weiterentwicklung des Java-Systems sollten die ClassNotFoundException-Enttäuschungen seltener werden.

13.4.7. Fernaufruf von Methoden

Seite 301

import java.rmi.*; // (13.15)
public interface KlubListe extends Remote {
	public String name (int mitgliedsnummer) throws NrUngueltigAusn, RemoteException;
	public int mitgliedsnummer (String name) throws RemoteException;
	public void eintragen (String name) throws RemoteException;
	public void loeschen (String name, int mitgliedsnummer) throws RemoteException;
}
import java.rmi.*; // (13.16)
import java.rmi.server.*;
import java.net.*;
public class KlubListeImpl extends UnicastRemoteObject implements KlubListe {
	private String[] liste;
	public KlubListeImpl(int laenge) throws RemoteException {
		super(); // throws RemoteException // erforderlich, um Ausnahme auszulösen
		liste = new String[laenge];
	}
	public String name(int nummer) throws NrUngueltigAusn, RemoteException {
		try {
			return liste[nummer];
		}
		catch (IndexOutOfBoundsException ausnahme) {
			throw new NrUngueltigAusn ();
		}
	}
	... // die weiteren Methoden aus der Schnittstelle ähnlich; main demnächst
KlubListeImpl klub = new KlubListeImpl();
public static void bind(String url, Remote r) throws RemoteException, AccesException,
	AlreadyBoundException, UnknownHostException;
public static void rebind(String url, Remote r) throws RemoteException, AccesException,
	UnknownHostException;
public static void unbind (String url, Remote r) throws RemoteException, AccesException,
	UnknownHostException, NotBoundException;
public static Remote lookup(String url) throws RemoteException, AccesException,
	NotBoundException, UnknownHostException;
public static String[] list(String url) throws RemoteException, AccessException,
	UnknownHostException;
Naming.rebind("rmi://ServerHost/VereinsRegister", klub);
Naming.rebind("VereinsRegister", klub); // gleich bedeutend
KlubListe c = (KlubListe)Naming.lookup("rmi://ServerHost/VereinsRegister");
System.setSecurityManager(new RMISecurityManager());
public static void main (String args[]) {
	System.setSecurityManager(new RMISecurityManager());
	try {
		KlubListeImpl klub = new KlubListeImpl(); // throws RemoteException
		Naming.rebind("VereinsRegister", klub); // throws RemoteException,
			// AccessException, UnknownHostException, MalformedURLException
		System.out.println("Klub-Server ist bereit.");
	} catch (Exception ausnahme) { System.err.println(ausnahme); }
}
import java.rmi.*; // (13.17)
public class KlubAussenstelle {
	public static void main (String args[]) {
		System.setSecurityManager(new RMISecurityManager());
		try {
			KlubListe liste = (KlubListe)Naming.lookup("rmi://Server/VereinsRegister");
			liste.eintragen("Otto Meierlein"); // eintragen in die entfernte Liste
			int nummer = mitgliedsnummer("Otto Meierlein"); // erhaltene Nummer holen
			String eintrag = liste.name(nummer); // entfernten Eintrag lesen
			System.out.println("Ferneintrag: " + eintrag + " M. Nr.: " + nummer);
		} catch (Exception ausnahme) { System.err.println(ausnahme); }
	}
}
rmic KlubListeImpl
start rmiregistry
java KlubListeImpl
java KlubAussenstelle

13.5. Ausblick

Seite 304


Nebenläufigkeit Inhaltsverzeichnis Hypertext-Version Literatur © APSIS GmbH