Java Einführung

  1. Allgemein: Java ist...
  2. Entwicklingszyklus: edit -> javac -> applet-tag, Tools, Links
  3. Applets & Applications
  4. Hello World
  5. Packages
  6. Die Klasse - Aufbau
  7. Spcifyers: private protected public static abstract final synchronized
  8. Interfaces
  9. Typen: Primitives, Objects, Wrapper
  10. Arrays, Strings
  11. Memory-Mangegement
  12. Operatoren, instanceof, this, super
  13. Programmablauf: if, switch, do-while, while, for, goto, break, continue, return
  14. Das (kurze) Leben der Applets
  15. GUI: Components & Containers, Components, Layout, Event Handling
  16. Zeichnen & Images
  17. Threads
  18. Exceptions
  19. Nützliche Klassen: Vector, Hashtable, Stack, Enumeration, System.out


Allgemein, Einleitung:

In dieser kurzen Zusammenfassung werden ich die wichtigsten Eigenschaften von Java unter dem Gesichtspunkt der Appletprogrammierung zusammenfassen. Dabei ist es auch Online zu lesen, da ich viele Links auf die Java-Dokumentationen bei uns in der TU-Chemnitz eingebaut habe. Die Dokumentationen stammen von Sun und sind sicher nach irgendeinem Copyright geschützt. Alle Warenzeichen sind Eigentum der jeweiligen Eigentümer....u.s.w.

Java ist eine Sprache, die als Bytecode compiliert auf einer Virtuellen Maschine abläuft. Damit wird eine Palattformunabhängigkeit erreicht. Der Syntax ähnelt dem von C, die Sicherheit ist ADA-like, von SmallTalk sind einige Konzepte der Objektorientierung verwendet worden.


Entwicklungszyklus:

  1. Schreiben des Quellcodes.
  2. Abspeichern unter filename.java
  3. Compilieren mit javac filename.java
  4. HTML-File schreiben.
  5. Abspeichern unter filename2.html
  6. Testen mit appletviewer filename2.html
  7. Mit javadoc eine Dokumentation erstellen

Das Applet-Tag: APPLET Tag

<applet class=filename.class codebase=dirname width=### height=### name=instanceName>
<param name=name1 value=value1>
<param name=name2 value=value2>
<param name=namen value=valuen>
Alternativer Text
</applet>

Nützliche Tools:


Applets & Applications:

Applets What Applets Can and Can't Do :

Applications:


Hello World:

import java.applet.Applet;
import java.awt.Graphics;

public class HelloWorld extends Applet {
    public void paint(Graphics g) {
        g.drawString("Hello world!", 50, 25);
    }
}

Alle Anweisungen werden mit einem Semikolon abgeschlossen (wie in C).

<HTML>
<HEAD>
<TITLE> A Simple Program </TITLE>
</HEAD>
<BODY>

Here is the output of my program:
<APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25>
</APPLET>
</BODY>
</HTML>


Packages:

Packages ähneln den Units in Pascal bzw. den includes in C. Die verschiedenen Klassen des JDK (in 1.0.2 etwa 210) werden zu Packages zusammengefaßt, um einen besseren Überblick zu haben, die Compilierung zu Beschleunigung und Namenskonflikte zu vermeiden. Wird nichts anderes angegeben, so gehört jede Klasse zum default-package.

Einbinden der Packages:

Java Packages:


Der Aufbau einer Klasse:

specifyer class MyClass extends ParentClass implements interface1, interface2,... {
}

Beispiel:

import java.awt.Point;
public class Rechteck [extends java.lang.Object] {
} 


Specifyers

Um den Zugriff auf Klassen, Attribute, Construktoren und Methoden zu beschränken wurden die Specifyers eingeführt.

Für Klassen gelten folgende drei: public, final, abstract.

public Alle Klassen können eine Instanz dieser Klasse anlagen - auch die außerhalb des Paketes. Standardmäßig ist eine Klasse nur innerhalb eines Paketes sichtbar.
final Von dieser Klasse kann keine Unterklasse erzeugt werden.
abstract Diese Klasse muß weiter abgeleitet werden, damit von ihr eine Instanz erzeugt werden kann.

Attribute, Construktoren und Methoden (kurz Members) werden durch folgende Specifyers beschränkt. Es gibt die Specifyers für Zugriff, Ableitung, Synchronisation, native Implementierung oder Statische Members

private Nur Objekte dieser Klasse dürfen auf die Members zugreifen - nicht einmal Subklassen. Standard ist der Zugriff nur von Klassen des gleichen Packages erlaubt.
protected Auch Subklassen in anderen Packages haben Zugriff auf diesen Member.
public Jeder Klasse hat vollen Zugriff auf den mit public gekennzeichneten Member.
final Ein so bezeichneter Member darf in einer Subklasse nicht überschrieben werden. (Anwendung, wenn eine final-Klasse zu "schwer" ist.
abstract Eine mit abstract Methode gekennzeichnete Methode muß in der Subklasse definiert werden. Ist ein Member einer Klasse abstract, so ist es auch die Klasse selbst.
synchronized Für diese Methoden wird ein Monitor angelegt. Damit wir die Synchronisation in Threads ermöglicht. Alle Klassen des JDK sind "threadsafe".
static Die so gekennzeichneten Member sind als Klassen-Attribute/-Methoden nur ein einziges mal pro Klasse verfügbar. Die Referenzierung kann auch mit ClassName.Member erfolgen.

Beispiele sind im Tutorial zu finden.


Interfaces:

Java unterstützt keine Mehrfach-Vererbung. Um aber trotzdem einen Teil dieser Funktionalität zu ermöglichen, wurden die Interfaces erfunden. Man kann sich ein Interface als eine Art vollständig abstrakte Klasse vorstellen. Jedoch dürfen nicht einmal Attribute in einem Interface definiert werden - nur Konstante. Bei Interfaces gibt es Mehrfach-Vererbung. Es ist auch möglich, ein Interface als Typ zu nutzen. (z.B. Thread(Runnable target))

Oft benutzte Interfaces:

Beispiel:


Typen:

Java unterscheidet zwei Arten von Typen: Referenzen und Primitives.


Arrays und Strings:

Arrays und Strings sind in Java Objekte.

Arrays

Strings


MemoryManagement:

Neue Objekte werden mit new angelegt. Nach new folgt ein Construktor. Es ist nicht möglich, Speicherplatz explizit freizugeben. Das mach der GarbageCollector. Ein Objekt wird entfernt, sobald es keine Referenz darauf meht gibt. Es wird automatisch der Virtuelle Speicher des Betriebssystems verwendet. Mit den Referenzen, die Java benutzt läßt sich nicht rechnen! Es sind eher Nummern, die einem Objekt zugeordnet werden.


Operatoren:

Es gelten die "normalen" C++ Operatoren. Die Prioritäten stehen hier.

  • +,-,*,/,%
Zum Rechnen mit Zahlen
  • &&,||,!
logische Ausdrücke
  • ++,--
als prefix oder postfix
  • <,<=,>,>=,==,!=
zum Vergleichen
  • >>,>>>,<<,&,|,^,~
für Bitmanipulation


Programmablauf:

if-then-else:

if (expr)
  anweisung1;
[else
  anweisung2;]

switch:

switch (ordinal) {
  case value1: anweisung1;break;
  case value2: anweisung2;break;
  ...
  case valuen: anweisungn;break;
  [default: anweisung_d;]
}

for:

for ([initialisierung]; [bedingung]; [iteration])  // komma ist möglich für "längere" ausdrücke
  anweisung;

while:

while (bedingung)
  anweisung;

do-while:

do {
  anweisung;
} while (bedingung);

goto:

Goto ist zwar ein reserviertes Schlüsselwort,. es wird aber nicht genutzt. Statt dessen können Schleifen mit labels versehen werden, die dann mit break oder continue verlassen werden.

break:

wenn mit break [label] eine Schleife verlassen wird, dann wird ans Ende der Schleife gesprungen und die Schleife verlassen

continue:

der Aufruf von continue [label] führt dazu, daß mit dem nächsten Schleifendurchlauf der Schleife fortgesetzt wird.

return:

mit return, return primitive, return Object werden Methoden verlassen. Der Parameter richtet sich nach dem Rückgabetyp der Methode. Return verläßt die Methode sofort, ohne die (möglichen) Anweisungen nach return zu berücksichtigen.


Der Lebenszyklus der Applets:

Es gibt 4 wichtige Methoden, die das Leben eines Applets beeinflussen. Das sind: init, start, stop, destroy.

Ein Applet braucht keinen Construktor. Es gibt auch noch weitere wichtige Methoden: paint(Graphics), handleEvent(Event), action(Event, Object).


GUI:

Components und Containers:

Das AWT (Abstract Window(ing) Toolkit) ist die Grundlage für die Graphische Oberfläche von Java. Es bildet die Schnittstelle zum Betriebssystem. Die einzelnen Elemente werden logisch in einer Baumstruktur angeordnet. Die graphische Verwaltung übernehmen Layoutmanager, die dafür sorgen, daß der Platz nach einer bestimmten Strategie verwendet wird. Die Elemente bestimmen ihre Größe selbst. Die Layoutmanager bestimmen dann die Lage auf dem Bildschirm. Es wird in Container und Components unterschieden. Jeder Container ist aber auch ein Component, so daß eine Verschachtelung möglich ist. Es wird die Methode add(Component) verwendet, um Components zu einem Container hinzuzufügen.Panel, Applet, Window, Dialog und Frame des Packages java.awt sind Container.

Komponenten (oder hier):

Das AWT stellt eine Reihe von GUI-Elementen zur Verfügung:

Dabei ist zu beachten, daß die Elemente je nach OS verschieden aussehen können. Das liegt daran, daß auf die GUI-Libraries der jeweiligen Systeme zurückgegriffen wird. Doch mit Hilfe der LayoutManager ist es kein großes Problem, die Elemente an die richtige Stelle auf den Bildschirm zu bekommen.

LayoutManager:

In Java überläßt man das Layout der Komponenten des GUI i.d.R. den Layoutmanagern. Mit der Methode setLayout(LayoutManager) wird einem Container ein Layout zugeordnet. Es gibt 5 verschiedene Layoutmanager:

  1. FlowLayout: Ist am einfachsten, alle Elemente werden von links oben nach rechts unten der Reihe nach angeordnet. Ist eine Zeile voll, wird auf der nächsten begonnen. Als Constructor-Parameter wird bestimmt, ob innerhalb der Zeilen linksbündig, zentriert oder rechtsbündig angeordnet werden soll.
  2. GridLayout: Dieses Layout unterteilt den Container in eine bestimmte Anzahl Zeilen und Spalten. Dabei wird der Container zeilenweise gefüllt. Als Parameter für den Constructor werden die Anzahl der Zeilen und Spalten übergeben.
  3. BorderLayout: Im Borderlayout besteht der Container aus 5 Abschnitten: Center, North, East, South und West. Einer dieser 5 Abschnitte muß der add(String, Component) Methode übergeben werden. Das Element im Center erhält die Priorität, wenn es "eng wird".
  4. GridBagLayout: Dieses Layout ist sehr kompliziert zu verwenden. Dafür hat es die meisten Gestaltungsmöglichkeiten. Allgemein läßt sich sagen, daß jedem Component noch ein GridBagConstraints-Objekt zugeordnet wird. In diesem wird dann genau angegeben, wie und wo das Component erscheinen soll. Es ist besser mit Absoluten Werten in den Constraints zu arbeiten. Es besteht zwar auch die Möglichkeit der relativen Anordnung, aber es ist noch komplizierter.
  5. CardLayout: Ein wenig anders als die 4 vorherigen ist das CardLayout. Es hat die Möglichkeit (wie z.B. in Windows) mehrere "Karten" auf Anfrage abwechselnd darzustellen. Auf jeder Karte wird i.d.R. ein einzelnes Panel gespeichert. Die einzelnen Panels werden dann durch Namen(Strings) unterschieden. Es wird add(String, Component) verwendet.

Diese Methode hat sich bei Verwendung des GridBagLayouts als sehr nützlich erwiesen:

Event Handling:

Java ist eine Eventgeteuerte Sprache. Jedes Component kann Events aussenden. Außerdem gibt es noch hardwarenahe Events wie MouseMove oder MouseDown oder die TastaturEvents. Alle Events werden vom OS an das Applet gemeldet. Das ermittelt das betroffene Component und gibt das Event an dessen handleEvent(Event). Es wird ein Baum entsprechend des GUI-Aufbaus abgearbeitet. Wird ein Event erfolgreich bearbeitet, so gibt handleEvent true zurück und die Bearbeitung ist zu ende. Beim Überschreiben von handleEvent ist es angebracht anstelle von false als letzten return-wert, super.handleEvent(Event) zurückzugeben. Das Component verteilt einige Events automatisch an andere Methoden:

Diese Methoden haben alle noch eine Reihe Extra-Parameter, die aber alle aus dem Event gefiltert werden.

Beispiel:


Zeichnen:

In Java wird nicht direkt auf den Bildschirm gezeichnet, sondern in einen Gerätekontext.

Jedes Component besitzt die Methode paint(Graphics g). Diese wird aufgerufen, wenn sich das Component zeichnen soll. Die Methode update(Graphics g) wird vorher aufgerufen. In ihr wird der Hintergrund gelöscht. Um bei Animationen ein Flackern zu vermeiden wird update oft umgeschrieben nach:

Images:

Es gibt verschiedene Methoden, um ein Image zu erzeugen:

Auf die leeren Images kann man dann zeichnen, indem man ein Graphics-Objekt anfordert. Da Images (java.awt.Image) auch Objekte sind, kann man sie in einer Datenstruktur zusammenfassen und damit Animationen erstellen.


Threads:

Als Thread werden Programmabläufe bezeichnet, die scheinbar gleichzeitig zu anderen Programmen im System ablaufen. In Java gehören Threads schon zur Sprache dazu. Sie werden durch die Klasse java.lang.Thread dargestellt. Die Arbeit verrichten Threads in einer run()-Methode. Es gibt 2 Varianten, einen Thread zu erzeugen:

  1. Ableiten einer neuen Klasse von Thread, überschreiben der run() Methode.
    1. MyThread extends java.lang.Thread() {
        public void run () {
           //do something
        }
      }
  2. Eine Instanz dieser Klasse anlegen:
    1. MyThread aMyThred =new MyThread();
  3. Und diesen starten:
    1. aMyThread.start();
  1. Bei der Erzeugung einer neuen Klasse, die das interface java.lang.Runnable implementiert:
    1. MyClass extends Object implements Runnable {
        public void run() {
          //do something
        }
      }
  2. Eine Instanz dieser Klasse anlegen:
    1. aMyClassInstance MyClass=new MyClass();
  3. Einen neuen Thead anlegen, der diese Klasse als Parameter bekommt:
    1. anOtherThread = new Thread(aMyClassInstance);
  4. Diesen starten:
    1. anOtherThread.start();

Jede dieser Methoden hat Vor- und Nachteile. Wenn man nur einen einzigen Thread hat, dann ist die Variante 2 besser. Variante 1 ist bei vielen Threads der gleichen Sorte zu empfehlen.

Es gibt dann noch die Möglichkeit, einen Thread zu stoppen (stop) und zu starten (start) bzw. zu anzuhalten (suspend) oder weiterlaufen zu lassen (resume). Alle Methoden stehen in der API-Doc erklärt.

Wichtig sind noch die Methoden yield() und currentThread(). Mit yield() wird der Thread gezwungen die Kontrolle abzugeben - ein anderer darf rechnen. Mit currentThread() (eine static-Methode von Thread) wird der aktuell laufende Thread ermittelt. Den Threads wird eine Priorität zugeordnet (max=10, min=0, norm=5). Die mit hoher Priorität erhalten Vorrang. Außerdem können Threads in einer ThreadGroup (java.lang.ThreadGroup) zusammengefaßt werden.


Exceptions:

Mit Exceptions hat Java eine sehr günstige Methode der Fehlerverarbeitung. Eine Exception ist ein Objekt (was sonst), daß im Falle eines unerwarteten Fehlers erzeugt und "aufgeworfen" wird. Irgendwo muß dann diese Exception gefangen werden. Wird dies nicht gemacht, so wird eine Ausgabe auf die Konsole erzeugt. Das Applet bricht aber nicht ab. (Es sei denn, es sind sehr schwerwiegende Gründe - Klasse nicht gefunden...)

Die Exceptions werden entweder mit einer try-catch-finally-Konstruktion abgefangen oder per throws-Statement nach "oben" delegiert:

try-catch:

Wenn innerhalb des try {} Blocks Exceptions entstehen, dann wird versucht, diese innerhalb des Catch-Blockes zu behandeln. Wenn nicht wird versucht, die Fehler weiterzureichen.

trows:

Ist ein Bestandteil des Methodenkopfes:

  Returntype Name (params) throws ExceptionType {
    ...
  }

Tritt in dieser Methode eine Exception auf, so wird diese automatisch an die rufende Methode weitergeleitet. Das try-catch hat aber innerhalb der Methode Vorrang vor throws.

Eigene Exceptions aufwerfen:

Eigene Exceptions werden von der Klasse Exception abgeleitet. Es reicht eigentlich schon, den Namen neu zu schreiben:

  MyException extends Exception {

  }  // das ist schon genug

Eine Exception kann auch vom Programmierer aufgeworfen werden. Dafür gibt es das Schlüsselwort throw - als Parameter erwartet es ein Throwable-Objekt: (Throwable ist eine Klasse, obwohl es nach Interface klingt - es ist die Oberklasse aller Exceptions und Errors)

  throw new MyException("Aus diesem Grund");

Errors sollten nicht "gefangen" werden, da sie auf schwere Fehler hinweisen.


Nützliche Klassen:

Zum Abschluß noch einige oft genutzte Klassen:

Allgemein bleibt nur zu sagen: Die Klassen sind der Kern der Sprache - wer sie kennt, der kennt Java - nur es kommen täglich neue dazu - in JDK 1.1.1. sind es schon 480...und die Entwicklung geht weiter.

Frame verlassen Zur Homepage

Chris Hübsch; 19.05.1997