Es ist kein homogenes Medium. Niemand kann es kontrollieren (sogar Bill
Gates nicht!) oder ausschalten. Mit Hilfe des Internet ist es möglich,
Informationen über alle denkbaren Themen zu besorgen, auch dann, wenn
irgendwelche nationale Gesetze oder Institutionen es verbieten. Man kann andere
Leute mit gleichen Interessen kennenlernen, Fragen stellen, Einkaufen usw. Das
Problem bei dieser Informationsfülle ist eben diese Informationsfülle. Es kann
sein, daß die gesuchten Informationen irgendwo im Netzt verfügbar sind, aber man
findet sie nicht. Man kennt nicht einmal alle Orte (Hosts), an denen man suchen
kann. Auch dafür wurden Werkzeuge geschaffen (Archie, Ways, Gopher). Im
allgemeinen gibt es drei Möglichkeiten:
Das WWW-Protokoll (HTTP - HyperText Transport Protokoll) implementiert ein hypertextorientiertes Verweissystem - HTML (Hypertext Markup Language), um auf andere Dokumente und Dateien zu verweisen, die ähnliche Themen beschreiben. Wählt man einen solchen Verweis aus, so wird automatisch das verwiesene Dokument geladen. So erspart man sich die Eingabe der entsprechenden Internetadressen, das Einloggen und Suchen in dem jeweiligen Verzeichnisbaum. Entsprechende Werkzeuge (WWW-Browser, z.B. NSCA Mosaic und Netscape) zeigen die Texte und Graphiken an und erleichtern die Arbeit. Den ersten WWW-Browser hat Tim Berners-Lee entwickelt. Er ist jetzt der Vorsitzender des WWW (oder W3C) - Konsortium, das über die weitere Entwicklung der WWW-Standards entscheiden soll. Alle großen Browserhersteller sind Mitglieder der W3C-Konsortium. Durch WWW-Standards soll gewährleistet werden, daß die Anwender mit ihrem Browser auch alle WWW-Seiten im Internet lesen können. Schließlich war dies das Ziel von WWW - ein protokollübergreifender Standard zu sein. Doch leider halten sich die meisten Browserhersteller aus Wettbewerbsgründen nicht daran. Jeder versucht, eigene WWW-Protokollelemente (Tags) zu erstellen, um die Anwender von den Vorteilen seines Browsers zu überzeugen.
Neue Protokolle sollen auch den Sicherheitsaspekt im Internet lösen. Durch die Verschlüsselung sollen private Internetpakete nur für den Empfänger lesbar sein. Die Sache ist etwas kompliziert durch die Exportbeschränkungen der US-Regierung, die "zu gute" Verschlüsselungsverfahren als eine Waffe einstuft und dadurch vom Export ausschließt. Außerdem sind verschlüsselte Telefonübertragungen in manchen Ländern (z.B. Frankreich) grundsätzlich verboten. Will man aber Bankgeschäfte über das Internet abwickeln oder einfach seine Kreditkartennummer dem Warenhaus übergeben, müssen diese Probleme gelöst werden.
In der Zukunft werden die Browser wahrscheinlich auch VRML (Virtual Reality Modelling Language) und Bildtelefonaufgaben erledigen können.
Probleme entstehen aber, wenn immer mehr spezifische Protokolle oder Dateiformate benutzt werden. Das Werkzeug müßte alle diese Protokolle und Dateiformate kennen oder ein Verweis auf ein anderes, lokal installiertes Programm haben, welches dieses Datenformat lesen kann. Dafür wurde das Werkzeug HotJava entwickelt.
Bild 1: Behandlung unbekannter Datenformate im HotJava Browser
Damit die Programme auf jedem Rechnertyp lauffähig sind, ist eine abstrakte Programmiersprache - Java - entwickelt worden. Diese Programme werden in HotJava interpretiert. Folgendes macht die Sprache sehr flexibel:
Vor kurzem wollte Microsoft noch eigene Konkurrenz-Standards (MSN
- Microsoft Network) für das Internet setzen. Nun aber soll Internet ein
integraler Bestandteil aller Microsoftanwendungen werden. Internet-Zugang soll
in alle Office-Applicationen eingebaut und Web-Server-Software standardmäßig
mit jedem Windows NT ausgeliefert werden. Access-Datenbanken liefern
automatisch fertige Internet-Seiten, ein Visual-Basic-Add-On erlaubt es,
Web-Design mit selbstprogrammierten Anwendungen zu verknüpfen. Folgende neue
Produkte sind geplant:
Novell Netware Anwender konnten bisher nicht über das Internet
miteinander kommunizieren. Der neue Netware Webserver füllt diese Lücke.
Eingebettet in SMP von Netware 4.1 garaniert der Webserver volles
Multiprozessing und ist nach Angaben von Novell zweimal schneller als ähnliche
Anwendungen unter Unix- oder Windows NT-Systemen. Netware Direct Services
kontrolliert Filesystem, Benutzeridentifikationen und Daten im Internet. Das
Adminstrationstool zum WWW läuft unter Windows.
Lotus hat einige Notes Marktanteile an WWW verloren, weil seine
Produkte zu teuer waren. Deshalb hat Lotus jetzt den Internotes Web Publisher,
der Notes-Datenbanken in HTML-Seiten für WWW umgewandelt, kostenlos für
Notes-Nutzer zur Verfügung gestellt. Lotus setzt auch auf Java bzw.
Javascript. Folgende neue Produkte sind geplant:
Oracle hat angekündigt, über ein Produkt namens Websystem Oracle
7 Datenbanken mit WWW zu verbinden. Das Websystem enthält auch einen
kostenlosen Powerbrowser und einen Personal Webserver für
Workgroup-Anwendungen. Er integriert die Java-Technologie von Network Loadable
Objects. Oracle bietet auch ein Internet-Commerce-Modul an, das Kunden,
Lieferanten und Distributoren mit neuesten Unternehmensinformationen versorgt.
Oracle setzt mehr auf Microsofts Visual Basic Script.
IBM's neueste OS/2 Version "Warp" enthält schon alle notwendige
Internet-Werkzeuge. Eine Neuentwicklung namens "Merlin" soll noch mehr
Netzwerkwerzeuge enthalten. Nach IBM's Meinung wird es in der Zukunft Benutzer
ohne Internetzugang gar nicht mehr geben!
Borland hat eine visuelle Entwicklungstool für Java namens
"Latte" für den zweiten Quartal 1996 angekündigt.
Sun hat eine neue Generation von speziellen Java-optimierten Chips angekündigt. Diese CPUs sollen den Output des Java-Compilers direkt und ohne den Einsatz einer Softwareschicht abarbeiten können. Deshalb können sie die Java-Programme schneller als andere CPU-s ausführen. Allerdings eignen sie sich auch nur für die Java-Applets. Als erster Chip soll die "Pico-Java" Mitte 1996 erscheinen. Dieser Chip soll unter 25 $ kosten und in Peripheriegeräten und Mobilfunktelephonen Einsatz finden. Der nächste Chip - "Micro-Java" wird wahrscheinlich im ersten Quartal 1997 erscheinen und ist mit einem Stückpreis zwischen 25 $ und 100 $ für Netzwerkgeräte, Buchungssysteme, Mail-Terminals und Spielkonsolen bestimmt. Schließlich am Ende 1997 soll ein Chip namens "Ultra-Java" erscheinen. Ultra-Java wird etwas über 100 $ kosten. Er soll aber auch 2D und 3D-Graphik, Audio, Vidokompression, Netzwerke und Verschlüsselung unterstüzen und ist für die zukünftige Internet-PCs bestimmt.
Bild 2: Ausführung von Java-Programmen
Kompilierte Java-Programme enthalten keine Adressen der Methodenaufrufe, sondern symbolische Links, die zur Laufzeit in Adressen umgerechnet werden (late binding). Dadurch kann man eine Oberklasse modifizieren, ohne alle davon abgeleiteten Klassen neu übersetzen zu müssen. Nur die Parameter und Namen der Methoden müssen gleich bleiben. Man kann aber auch neue Methoden hinzufügen. Das Linken geht sehr schnell und kann deshalb auf dem Zielsystem zur Laufzeit erfolgen.
Der Java-Klassen-Loader durchsucht immer zuerst das lokale System, um Namensreferenzen aufzulösen. Dadurch kann keine externe Klasse mit demselben Namen ein Sicherheitsrisiko für das Zielsystem werden. Doch auch dann traut der Java-Interpreter keinem Code. Jeglicher Code (auch lokale Klassen) wird vor der Ausführung verifiziert, um unbefugte Modifikationen des Speichers (überschreiten der Arraygrenzen usw.), Verletzungen der Zugriffsrechte (private, protected, public), Stackoverflows usw. zu entdecken.
Java enthälten Sprachelemente für die nebenläufige Ausführung von Programmteilen (Klassen: Thread, Runnable, etc.) sowie Kontrollmaßnahmen, um die nebenläufige Ausführung der Programmteile zu koordinieren (synchronised).
Bald entschied man sich, für die kleinen Java-Programme Internet als Transportmedium zu benutzen. Mit Hilfe der Java-Programme kann man die WWW-Seiten interaktiv und beliebig konfigurierbar gestalten. Java-Programme verringern auch die Netzbelastung. Dynamische WWW-Seiten (z.B. Börsenkurse, Versandhausangebote usw.) werden vor der Übertragung zu einem Bild zusammengefaßt, dann als Rasterbild übers Internet transportiert. Nun braucht man nur noch die wenige relevanten Informationen und (beim ersten Zugriff ) das entsprechende Programm zu übertragen. Auf der Clientseite wird aus den Daten das Bild zusammmensetzt. Javas virtuelle Maschine ist eine Stackmaschine.
Bild 3: Vergleich von Java mit anderen Programmiersprachen. Quelle: Sun Microsystems
In der Programmiersprache Java hat man versucht, die besten Eigenschaften von C++, SmallTalk, Oberon, Eiffel, Perl und anderen Programmiersprachen zu vereinen. Es ist ein Kompromiß zwischen einer hohen Ausführungsgeschwindigkeit, guter Portierbarkeit und Felxibilität.
In der Programmiersprache Java kann man Applets erstellen, die man in WWW-Seiten einbinden kann. Diese Applets implementieren interaktive Komponenten der WWW-Seite. Sie können auf Benutzereingaben reagieren und beliebige Aktionen durchführen. Da sie ihre Daten selbst anzeigen, können somit (genau wie mit OLE und OpenDoc) beliebige Daten gemischt werde. Darüber hinaus muß bei Java das genaue Datenformat dem Client nicht bekannt sein. Falls er dieses Datenformat noch nicht kennt, so lädt er vom Server das entsprechende Programm dazu. Eines der Ziele von Java war auch, mit Hilfe der Applets den Netzwerkehr zu verringern. Man kann statt kompletter Rasterbilder (Geschäftsgraphiken, Börsenkurse usw.) nur die nummerische Daten und falls notwendig ein Java-Programm übertragen, das das Bild auf der Clientseite erstellt. Java-Applets sind in einer WWW-Seite nicht miteinander verbunden, sondern akzeptieren nur die Eingaben und Verantwortung über ihren eigenen Bereich auf der WWW-Seite. Um Applets miteinader zu verbinden, kann man die Programmiersprache JavaScript benutzen. OLE und OpenDoc sind inzwischen ebenfalls netzwerkfähig. Java ist es schon von Grund auf. Außerdem unterstützt Java Threads und Hintergrundbearbeitung. Fazit: Mit Java lassen sich viele ähnliche Aufgaben wie mit OLE oder OpenDoc realisieren, aber es ist nicht mit diesem Ansatz entwickelt worden.
Eine Quelldatei kann aus folgenden Elementen bestehen:
Legt fest, zu welchem Package diese Klasse gehört. Fehlt die
package Anweisung, gehört die Klasse zu einem namenslosen Package. So kann man
schnell Klassen implementieren, Testen und später unter einem global
eindeutigen Packagenamen freigeben. Die global eindeutigen Packagenamen
sollten wie Internetadressen aussehen z.B.
DE.TU-ILMENAU.PRAKINF.TESTAPP. Packages sind wie Bibliotheken in C++.
Pro Quelldatei darf nur eine öffentliche Klasse oder Interface deklariert
sein, aber mehrere Quelldateien können zu einer Package gehören.
Importiert ein anderes Packages, das diese Klasse verwendet bzw.
von dem es abgeleitet ist.
Die Zeilen der Quelldateien werden durch die ASCII-Zeichenkombination
<CR><LF> terminiert. Der Java-Compiler überliest beim Kompilieren
alle Leerzeichen, horizontale und vertikale Tabulatoren sowie Zeilenenden und
Kommentare. Als Kommentare gelten:
abstract do implements package throw boolean double import private throws break else inner protected transient byte extends instanceof public try case final int rest var cast finally interface return void catch float long short volatile char for native static while class future new super byvalue const generic null switch continue goto operator synchronized default if outer thisDie Wörter byvalue, cast, const, future, generic, goto, inner, operator, outer, rest und var sind zwar reserviert, werden jedoch nicht benutzt.Die Namen von Variablen, Klassen und Methoden sind beliebig lange Unicode-Zeichenketten, beginnend mit einem Zeichen und gefolgt von Zeichen und Nummern.Literale sind Werte von primitiven Datentypen und die Klasse String.
= > < ! ~ ? : == <= >= != && || ++ -- + - * / & | ^ % << >> >>> += -= *= /= &= |= ^= %= <<= >>= >>>=
Bei ganzahliger Division durch 0 wird eine ArithmeticException ausgelöst. Bei gebrochenen Zahlen entsteht bei der Division durch 0 Unendlich und es wird keine Exception ausgelöst. Negative und Positive 0 sind gleich (0.0 == -0.0).Instanzen und Arrays müssen immer durch den new Operator dynamisch allokiert werden. Variable, die Instanzen enthalten, sind immer Refrenzen. Arrayelemente dürfen Arrays, Interfaces, Instanzen oder primitive Typen sein. Als Indizes benutzt man ganze Zahlen.
0. Host's Packages 1. Quelldatei 2. Datentyp (Klasse oder Interface Deklaration) 3. Parameter der Methode 4. lokaler Block 5. for BefehlBeim Auflösen einer Namensreferenz wird in dieser Hiearchie von unten nach oben gesucht. Der Zugriff auf Instanzvariablen wird folgendermaßen bestimmt:
import java.applet.Applet; // Importiert die Klasse Applet import java.applet.*; // Importiert alle Klassen und Interfaces // aus dem Package java.appletOhne einen Importbefehl kann man die Klassen nicht benutzen. Der Compiler gibt eine Fehlermeldung aus. Allerdings wird die Klasse java.lang immer implizit importiert.
[<Doc-Komment>] [<Klassentyp>] class Klassenname
[extends <Oberklasse>]
[implements <Interfaces>]
{ <Felder>};Zum Beispiel: /** Person */public class Person {
public String m_strVorname;
public String m_strNachname;
};
/** Programmierer */
class Programmierer extends Person implements Arbeitnehmer {
public float m_fGehalt;
public float HatGehalt() { return m_fGehalt; }};Klassentyp
kann sein:
Man kann Referenzen zwischen einer Ober- und Unterklasse umdefinieren. Wenn die Klasse A eine Unterklasse von B ist, so kann man einen Referenz vom Typ A ohne explizite Redefinition als eine Referenz von Typ B zuweisen. In die andere Richtung muß man eine explizite Typumwandlung stattfinden. Zum Beispiel:
A a; B b; a = b; b = (A)a;Felder können Variablen- und Methodendeklarationen sein. Methodendefinitionen haben die Form:
[<Doc-Komment>] [<Methodentyp>] [<Rückgabetyp>] <Methodenname>
[throws <Exceptions>] ([<Parameterliste>])
{ <Methodenkörper>
}Konstruktoren haben denselben Namen wie die Klasse, in der sie deklariert
sind. Konstruktoren haben keinen Rückgabewert. Falls kein Konstruktor deklariert
wird, so erhält die Klasse implizit einen Konstruktor (public und ohne
Parameter). Instanzen werden mit dem Operator new angelegt. Java-Klassen
haben keinen Destruktor, können aber eine finalize() Methode haben. Der
Speicher von Instanzen wird vom Garbage-Collector freigegeben, wenn die
Instanzen nicht mehr referenziert werden. Die Methode finalize() wird vom
Garbage-Collector nur einmal aufgerufen. In dieser Methode können
Betriebssystemressourcen (Graphics Contexc, Brushes, Pens, Dateideskriptoren
usw.) freigegeben oder die Freigabe der Instanz verzögert werden.Die Freigabe
der Instanz wird verzögert, indem eine Referenz auf diesen Instanz in einer
Variable abgelegt wird.
Alle Exceptions, die in dieser Methode auftreten können und nicht vom Typ Error oder RunTimeException sind, müssen deklariert werden. Alle Exceptions müssen von Throwable abgeleitet sein.
Eine Methode darf keine lokale Variable definieren, die den gleichen Namen verwendet, wie einer ihrer Parameter. Überladene Methoden müssen unterschiedliche Paramaterlisten haben. Ein unterschiedlicher Rückgabetyp ist nicht aureichend. Mathematische Operatoren dürfen nicht überladen werden.
Die Zugriffsrechte auf Methoden werden durch die Schlüsselwörter public, private und protected festgelegt. Wird nichts angegeben, so sind die Methoden innerhalb des Package öffentlich. Als final deklarierte Methoden dürfen nicht überschrieben werden. Solche Methoden erlauben dem Kompiler, Optimierungen vorzunehmen (z.B. Ersetzen der Methodenaufrufe mit seinem Körper). Abstrakte Methoden haben keinen Methodenkörper und müssen in einer abgeleiteten Klasse implementiert sein. Als native deklarierte Methoden haben keine Methodenkörper (in Java) und müssen in eine anderen Programmiersprache (z.B. C) implementiert werden. Statische Methoden sind Klassenmethoden, d.h. sie können nur auf Klassen (statische) Variablen zugreifen und können vor dem Instanziieren aufgerufen werden. Das Schlüsselwort synchronised deklariert eine Methode oder umschließt einen Block und wird durch einen Monitor vor der gleichzeitigen Ausführung geschützt.
Instanzvariablen haben Zugriffsrechte (private, protected, public, "friendly"), einen Datentyp, Initialisatoren. Falls die Instanzvariablen nicht explizit initialisiert werden, setzt der Java-Interpreter sie je nach Typ auf 0, false, '\0' oder "". Java-Klassen können auch Initialisierungsblöcke enthalten. Das sind statische Codeblöcke, die zur Initialisierungszeit ausgeführt werden. Zum Beispiel:
class Test extends A {
int x = 2;
float f = 0.34;
String str = "das ist ein " + "Test";
int y;
{ //statischer Initialisierungsblock
x = 4; //Überschreibt die Anfangswerte.
f = 3.67;
y = "das ist ein".length();
}
public Test(int x, float g, String s) {
super(s); //Aufruf des Konstruktors der Basisklasse
this.x = x; //hier muß man mit this.x die Instanzvariable
//adressieren, weil der Parameter auch x heißt.
f = g; //zum dritten Mal initialisieren
y = 23;
}
};In diesem Beispiel werden die Instanzvariablen insgesamt dreimal
initialisiert. Zum ersten werden sie durch eine direkte Zuweisung initialisiert.
Die Instanzvariable y hat keinen direkte Initialisator und wird deshalb mit 0
belegt. Anschließend wird der statische Initialisierungsblock ausgeführt. Es
kann beliebig viele solche Initialisierungsblöcke geben und sie werden alle in
der Reihenfolge ausgeführt, wie sie in den Klassendeklarationen vorkommen.
Schließlich werden die Instanzvariablen auch in dem Konstruktor initialisiert.
Hier ist auch zu sehen, wie man den Konstruktor der Basisklasse aufruft -
super(<Argumente>); . Der Konstruktor der Basisklasse kann auch
implizit aufgerufen werden, falls die Basisklasse einen parameterlose
Konstruktor besitzt. In diesem Beispiel ist weiterhin zu sehen, wie Strings
behandelt werden. Der Kompiler ersetzt zur Kompilezeit jede Zeichenkette durch
eine Instanz der Klasse String. Da die Klasse String einen + Operator hat, kann
man die Zeichenketten mit + verbinden. Außerden kann man für Zeichenketten
gleich eine Methode der Klasse String aufrufen. Man könnte die String -
Variablen auch folgendermaßen intialisieren:
String str = new String("das ist ein Test");
Das ist aber nich so effizient, denn in diesem Fall erzeugt der Kompiler aus der Zeichenkette einen String und übergibt diesen einem weiteren Konstruktor der Klasse String.
Parameternamen, die den gleichen Namen als ein Instanzvariable haben, verdecken diesen. Diese Instanzvariablen kann man dann mit this (oder super für Basiklasse) adressieren. Instanzvariablen und Methoden werden mit <Instanzname>.<Feldname> adressiert. Statische Varibalen und Methoden werden mit: <Klassenname>.<Feldname> adressiert.
Variablen können auch folgendermaßen deklariert sein:
[<Interfacetyp>] interface <Interfacename> {
<Felder>};Zum
Beispiel: public interface Arbeitnehmer {
public float HatGehalt();
};Interfaces legen ein gemeinsames Teilverhalten für mehrere Klassen
fest, die so nicht viel voneinander wissen müssen. So kann man z.B. für
Arrayelemente ein gemeinsames Interface definieren, ohne alle Elementklassen von
einer gemeinsamen abstrakten Oberklasse abzuleiten. Interfaces können private
(default) oder public sein. Alle Methoden in Interfaces sind immer public und
abstract und alle Variablen in Interfaces sind immer static, public und final.
Methoden in Interfaces dürfen nicht synchronised, transient oder volatile sein.
Interfaces verhalten sich beim Anlegen von Instanzvariablen genauso wie Klassen.
Da der eigentliche Typ hierbei aber erst zur Laufzeit ermittelt wird, sind sie
etwas langsamer.
Der Schlüsselwort this verweist auf diese Instanz und das
Schlüsselwort super auf die Oberklasse. Wenn in einer Unterklasse eine
gleichnamige Instanzvariable deklariert wird, so wird die Instanzvariable der
Oberklasse nicht überschrieben, sondern nur unsichtbar gemacht. Man kann diese
mit Hilfe der Schlüsselwortes super adressieren. Dasselbe gilt für Methoden.
Marke1 : while(true) {
while(true) {
if(<Bedingung>)
continue label1;
}
}Der letzte Sprungbefehl
springt aus dem inneren Block. Die speziellen Labels case
<Bedingung>: und default dürfen nur innerhalb eines
switch Blockes auftreten. Der continue Befehl kann nur Labels
aktivieren, die auf Iterationsbefehle verweisen. Die Labels in einfachen
Anweisungen können nur mit break und continue Befehlen innerhalb
eines Blockes aktiviert werden. Blöcke können sowohl Anweisungen, als auch
lokale Variablendeklarationen enthalten. Anweisungen werden mit einem Semikolon
terminiert. Blöcke könne überall dort existieren, wo auch Anweisungen stehen.
switch ( Anweisung ) {
case <Konstante Anweisung>: Anweisung
...
default:
}Bei den Operatoren sind nur + für das Verbinden von Strings und >>> für ein vorzeichenloses Leftschift neu. Das Resultat von n>>>s ist gleich dem n>>s, falls n größer null ist, sonst aber (n>>s)+(2<<(k-s-1)), wobei k 32, falls n vom Typ int und 64, falls n vom Typ long ist.
In der Programmiersprache Java hat man zwei Möglichkeiten, Threads zu
benutzen. Man kann seine Klasse von der Klasse Thread ableiten oder als
Implementierung das Interface Runnable definieren. Beide Möglichkeiten
haben ihre Vor- und Nachteile. Im allgemeinen: falls eine Klasse von einer
anderen Klasse ableiten muß, zum Beispiel von der Klasse Applet, dann kann sie
nur das Interface Runnable benutzen. Anderenfalls sollte sie von der Klasse
Thread abgeleitet sein.
//
// SimpleThread.java
//
class SimpleThread extends Thread {
public SimpleThread(String name) {
super(name);
}
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((int)Math.random() * 1000);
} catch(InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}Listing 1: Listing von SimpleThread.java. Quelle: JDK 1.0
beta2 //
// TwoThreadsTest.java
//
class TwoThreadsTest {
public static void main(String args[]) {
new SimpleThread("Jamaica").start();
new SimpleThread("Fiji").start();
}
}Listing 2: Listing von TwoThreadsTest.java. Quelle: JDK 1.0
beta2
In diesem Beispiel wird eine Unterklasse von Thread - SimpleThread - definiert, die 10 Mal ihren Namen auf den Standardausgabestrom schreibt und dann eine zufällige Anzahl von Sekunden wartet. Durch den Aufruf der Methode sleep() erhält der andere Thread die Möglichkeit zum Laufen. Die Threads haben gleiche Prioritäten und würden sonst nicht abwechselnd aktiviert.
Die Benutzung von Runnable Interface wird in dem Kapitel "Ein einfaches Java-Applet" demonstriert.
Jeder Thread muß eine Methode run() haben, die den Code für den
Hintergrundprozess enthält. Threads haben einen Zustand (runnable, not runnable,
dead, new thread) und eine Priorität. Java's virtuelle Maschine implementiert
ein einfaches prioritätsgetriebenes Scheduling. Zu jeder Zeit läuft der Thread
mit der höchsten Priorität. Falls mehrere Threads mit gleicher Priorität gerade
lauffähig sind, so wählt der Scheduler den ersten und läßt ihn laufen. Der
Thread wird nicht abgerochen, um andere Threads mit gleicher Priorität laufen zu
lassen, es sei denn, daß das Ziel-Betriebssystem eine solche
Schedulingsstrategie implementiert. Alle Threads gehören zu Gruppen, die
gemeinsame Eigenschaften haben. Threads können Daemons sein. Daemons sind
Threads, die im Hintergrund mit einer niedrigeren Priorität laufen und Aufgaben
auf Anfrage von anderen Threads erledigen.
Bild 4: Zustände der Java-Threads
Wenn ein Java-Thread angelegt wird, ist er in dem Zustand New Thread. Mit einem Aufruf der Methode start() wird der Thread in den Zustand Runnable überführt. Runnable Threads werden vom Scheduler ausgeführt, wenn CPU-Zeit frei ist. Ein Thread kann die Kontrolle über die CPU freiwillig mit der Methode yield() abgeben, um andere Threads mit gleicher Priorität laufen zu lassen. Der Thread kann jederzeit mit der Methode stop() angehalten werden. In diesem Zustand ist er nicht mehr lauffähig. Man kann aber seine Instanzvariablen lesen. Threads können zeitweilig mit der Methode suspend() angehalten und anschließend wieder mit der Methode resume() gestartet werden. Threads, die auf einen Monitor warten (Methode wait()), müssen ein Signal vom Monitor (Methode: notify()) erhalten, um wieder laufen zu können.
Die Methode isAlive() liefert true, wenn der Thread gestartet und noch nicht gestoppt wurde (Zustand runnable oder not runnable). Die Priorität eines Threads kann man mit Hilfe der Methode setPriority() setzen. Die Priorität muß zwischen MIN_PRIORITY und MAX_PRIORITY liegen (Konstanten der Klasse Thread). Die Methode isDaemon() liefert true, wenn der Thread ein Daemon-Thread ist. Um einen Daemon-Thread zu erzeugen, muß man die Methode setDaemon() mit dem Wert true aufrufen. Die run()-Methode der Daemon-Threads ist typischeweise eine ewige Warteschleife auf Anfragen von anderen Threads.
Für die Synchronisation von Threads bietet Java wiedereintrittsfähige
Monitore.
//
// Producer.java
//
class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for(int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number + " put: " + i);
try {
sleep((int)(Math.random() * 100));
} catch(InterruptedException e) {}
}
}
}Listing 3: Listing von Producer.java. Quelle: JDK 1.0 beta2
//
// Consumer.java
//
class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for(int i = 0; i < 10; i++) {
value = cubbyhole.get(i);
System.out.println("Consumer #" + this.number + " got: " + value);
}
}
}Listing 4: Listing von Consumer.java. Quelle: JDK 1.0 beta2
//
// CubbyHole.java
//
class CubbyHole {
private int seq;
private boolean available = false;
public synchronised int get() {
while(available == false) {
try {
wait();
} catch(InterruptedException e) {}
}
available == false;
return seq;
}
public synchronised void put(int value) {
seq = value;
available = true;
notify();
}
}Listing 5: Listing von CubbyHole.java. Quelle: JDK 1.0 beta2
//
// ProducerConsumerTest.java
//
class ProducerConsumerTest {
public static void main(String args[]) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}Listing 6: Listing von ProducerConsumerTest.java. Quelle: JDK 1.0
beta2
In diesem Beispiel sieht man die Verwendung von Monitoren. Die Klasse
Producer erzeugt 10 ganze Zahlen, schreibt sie in eine Puffer (CubbyHole) und
wartet dann ein zufällige Zeit. In dieser Zeit wird der Consumer aktiv und holt
sich die neueste Zahl. Die Klasse CubbyHole definiert die synchronisierten
Methoden get() und put(). Java erzeugt für jede Instanz einer Klasse, die
synchrosniserte Methoden oder Codeblöcke enthält, einen Monitor. Wenn ein Objekt
eine solche Methode aufruft, sperrt es automatisch den Monitor und gibt ihn nach
Verlassen der Methode wieder frei. Falls das Objekt in dieser Methode wait()
aufruft, wird der Monitor ebenfalls freigegeben. Das Objekt sperrt den Monitor
wieder, sobald es in den Zustand runnable zurückkehrt.
//
// TestApp.java
//
class TestApp {
public static void main(String args[]) {
System.out.println("Test App!");
}
}Listing 7: Listing von TestApp.java. Quelle: JDK 1.0 beta2
Nach der Kompilierung wird daraus die Binärdatei TestApp.class erstellt, die man anschließend mit dem Java-Interpreter ausführen kann:
javac TestApp.java
java TestApp
//
// TestApplet.java
//
import java.awt.Graphics; //graphische Klassen
import java.applet.Applet; //Deklaration der Klasse Applet
public class TestApplet extends Applet {
public void init()
{ resize(150, 25); }
public void paint(Graphics g)
{ g.drawString("Ausgabe von Test Applet!", 50, 25); }
}Listing 8: Listing von TestApplet.java. Quelle: JDK 1.0 beta2
Diesen Quellcode kompiliert man mit den Java-Compiler (javac). Dazu gibt man auf der Kommandozeile den Befehl:
javac TestApplet.java
ein . Der Java-Compiler erzeugt die Datei TestApplet.class. Die neue Klasse muß jetzt in eine WWW-Seite eingebunden werden, zum Beispiel so:
<HTML>
<HEAD>
<TITLE> "Titel" </TITEL>
</HEAD>
<BODY>
"Das ist ein Applet!"
<APPLET CODE=TestApplet.class WIDTH=150 HEIGHT=25>
</BODY>
</HTML>
Listing 9: Listing von TestApplet.html. Quelle: JDK 1.0 beta2
Nun kann man die neue WWW-Seite in den Browser laden. Man sollte den Browser nicht aus dem Verzeichnis, in dem die WWW-Seiten gespeichert sind, aufrufen. Sonst kann man die Datei - nach einigen Programmänderungen - nicht erneut laden.
Damit die Applets quasiparallel ablaufen können und sich nicht
gegenseitig blockieren, sollte man für längere Abläufe in Applets
Hintergrundthreads benutzen. Dafür muß das Applet zusätzlich von der Klasse
Runnable abgeleitet sein. Hier ein kleines Beispiel:
//
// ThreadApplet.java
//
import java.awt.*;
import java.applet.Applet;
public class ThreadApplet extends Applet implements Runnable {
Thread testThread = null;
int count = 0;
String meldung = null;
public void run() {
while(true) {
sleep(100);
count++;
meldung = "Schleifenzähler: " + count;
repaint();
}
}
public void paint(Graphigc g) {
g.clearRect(0,0,size().width-1, size().height-1);
g.drawString(meldung, 5, 15);
}
public void init() { resize(500, 20); }
public void start() {
if(testThread == null) {
testThread = new Thread(this, "Test Thread");
testThread.start();
}
}
public void stop() {
testThread.stop();
testThread = null;
}
}Listing 10: Listing von ThreadApplet.java. Quelle: c't 2/96
Die JDK Version 1.0 beta2 unterstützt nur die Implementierung der
"Native-Methods" in der Programmiersprache C. Eine "native methode" deklariert
man in der Java-Klasse ohne eine Implementierung. Um die Methodendeklaration mit
der Implementierung zu verbinden, muß man in einem statischen
Initialisierungsblock mit Hilfe der Methode loadLibrary() der Klasse
System eine DLL (oder shared Library unter UNIX) mit der Implementierung laden.
//
// HelloWorld.java
//
class HelloWorld {
public native void displayHelloWorld(); //native Methode deklarieren
static {
System.loadLibrary("hello"); //DLL mit implementierung laden
}
public static void main(String args[]) { //Hauptprogramm
displayHello();
}
}Listing 11: Listing von HelloWorld.java. Quelle: JDK 1.0
beta2
Diese Quelldatei kann man ganz normal (javac HelloWorld.java)
kompilieren. Für die Implementierung in C muß man mit Hilfe des Programms javah
aus der Java-Klasse eine Headerdatei und eine Stubs-Datei generieren.
javah HelloWorld //erzeugt HelloWorld.hjavah -stubs HelloWorld //erzeugt HelloWorld.c
Das Programm javah generiert eine HelloWorld.h-Datei, die eine C-Struct
enthält und eine externe Funktion deklariert. Dieses Struct hat die Aufbau der
Java-Klasse und ermöglicht der C-Methode, auf die Instanzvariablen der
Java-Klasse zuzugreifen. Die generierte Stub-Datei enthält den Rumpf der C -
Funktion, die als Java-Methode aufgerufen wird. Aus dieser Datei erzeugt man die
DLL.
// // HelloWorld.c // #includeListing 12: Listing von HelloWorld.c. Quelle: JDK 1.0 beta2#include "HelloWorld.h" #include void HelloWorld_displayHelloWorld(struct HHelloWorld *this) { printf("Hello World!\n"); return; }
Die Headerdatei StubPreamble.h enthält Deklarationen des internen Java-Laufzeitsystems für die C-Funktion. Die Headerdatei HelloWorld.h enthält die Deklaration der C-Struct, die der Java-Klasse entspricht. Ein Zeiger auf diese Struct wird der C - Funktion übergeben, damit sie auf die Instanzvariablen der Java-Klasse zugreifen kann.
Die kompilierte DLL muß in einem Verzeichnis liegen, das in der PATH
Umgebungsvariable angegeben ist. Unter UNIX muß man die Umgebungsvariable
LD_LIBRARY_PATH entsprechend setzen.
Sowohl Netscape als auch Microsoft haben angekündigt, solche
Scriptsprachen zu entwickeln. Microsofts Scriptsprache soll Visual-Basic-Script
heißen und auch Windows-Systemaufrufe durchführen können. Netscape hatte vorher
eine eigene Scriptsprache namens LiveScript entwickelt. Nach einer Vereinbarung
mit Sun wurde diese Sparche zu JavaScript umbenannt und ist jetzt in der
neuesten Version des Netscape Browsers eingebaut. JavaScript ist noch nicht ganz
fertig. Viele Sprachelemente sind entweder noch nicht implementiert oder nicht
dokumentiert. Außerdem hat man viele weitere Änderungen an der Sprache
angekündigt.
Bild 5: Objekthierarchie der Programmiersprache JavaScript
Die Formularelemente haben folgende Ereignis-Handler und Methoden:
| Ereignis-Handler | Methode | Bedeutung |
|---|---|---|
| onBlur | blur | Verlassen des Feldes |
| onChange | - | Ändern des Feldinhaltes |
| onClick | click | Mausklick auf den Button |
| onFocus | focus | Aktivieren eines Textfeldes |
| onLoad | - | Ausführen von JavaScript-Code |
| onMouseOver | - | Mausbewegung über das Feld |
| onSelect | select | Auswählen eines Select-Feldes |
| onSubmit | - | Abschicken eines Formulars |
| onUnload | - | Ausführen von JavaScript-Code |
| - | enable | Erlauben der Benutzereingabe |
| - | disable | Verbieten der Benutzereingabe |
Tabelle 1: Ereignis-Handler und Methoden der Formularelemente
Listing 13: einfaches JavaScript Beispiel. Quelle: iX 2/96
Das JDK enthält einen Compiler (javac), einen zeichenorientierten Debugger (JDB) und ein paar andere Tools. Die Dokumentation gibt es ebenfalls kostenlos übers Internet von Sun (http://java.sun.com). Im Moment ist es möglich, die Dokmentation als Postscript- oder HTML Format downzuloaden. Die Dateinamen sind jedoch länger als 13 Zeichen.
Als Einführung in die Java-Programmierung ist das Java Tutorial durchaus zu empfehlen. Die Sprachspezifikation ist mehr trocken gehalten.
Die erste Java-Entwicklungsumgebung kommt von Symantec (Espresso). Es handelt sich dabei im wesentlichen nur um die Einbindung des JDK von Sun in das Symantec C++-Projektmanagement.
Borland hat eine visuelle und leicht bedienbare Entwicklungsumgebung für Java (Latte) angekündigt. Latte soll Mitte des Jahres erscheinen.
Java-Klassenbrowser gibt es schon als Shareware.