Was ist Java ?

Mit dem Durchbruch von HTML (Hyper Text Markup Language) haben Informationsdienste über das Internet/World-Wide-Web (WWW) eine grosse Verbreitung gefunden. Allerdings war HTML ursprünglich nur für die Veröffentlichung von Dokumenten gedacht. Es gibt zwar inzwischen mit CGI eine programmierbare Erweiterung zu HTML, allerdings sind dabei die Möglichkeiten ziemlich begrenzt.
Mit der Programmiersprache Java wurde eine Möglichkeit gefunden, vollwertige Programme über ein Netzwerk auszuliefern und auf beliebigen Architekturen zu starten.
Inzwischen haben Firmen wie Microsoft (mit ActiveX) oder Netscape (mit javascript) ähnliche Konzepte verwirklicht, allerdings bietet bisher nur Java (das von der Firma SUN entwickelt wurde) Herstellerunabhängigkeit, weil alle Schnittstellen veröffentlicht wurden und es schon freie Implentierungen der Sprachübersetzer gibt.

Exkurs: Geschwindigkeit von java

In der Kürze der Zeit lässt sich natürlich nicht die ganze Sprache Java erschöpfend behandeln. Das Ziel des Kurses ist vielmehr, die grundlegenden Konzepte verstanden zu haben und einfache Anwendungsprogramme schreiben zu können.

Umgang mit einfachen Java Programmen

Ein Javaprogramm wird mit dem Befehl

   javac Klassenname.java 

in eine Form übersetzt, die später von verschiedenen Programmen auf verschiedenen Rechnern ausgefuehrt werden kann.

Einfache Programme ohne Graphik können mit dem Befehl

   java Klassenname 

ausgeführt werden.

Programme mit Graphik (sogenannte Applets) können mit Programmen wie appletviewer oder netscape ausgeführt werden (darauf wird später noch mal eingegangen).

Übung 1:

Speichern Sie das folgende einfache HelloWorld-Programm unter dem Namen HelloWorld.java ab, compilieren Sie es und führen Sie es aus.

    class HelloWorld 
       {
       public static void main (String args[]) 
          {
          System.out.println("Hello World!");
          }
       }
Download HelloWorld.java
   javac HelloWorld.java 
   java HelloWorld 
Java sucht nach ".class" Bytecodeprogrammen entweder über die Environmentvariable CLASSPATH oder die option -classpath.
Lassen Sie sich diese Variable (Unix: echo $CLASSPATH Windows: echo %CLASSPATH% auf dem Schirm anzeigen. Lassen Sie den Pfad . weg und benutzen sie das Resultat (am besten über cut and paste) für die -classpath option.
(unter Unix können Sie das alles in einer Zeile mit dem Befehl
java -classpath `echo $CLASSPATH | sed 's/\:\.//g' | sed 's/\.\://g'` HelloWorld 
automatisieren)

Welche Fehlermeldung tritt auf ?

Java Syntax

Java ist der Sprache C sehr ähnlich, hat aber eine leicht veränderte Syntax.

Die wichtigsten Unterschiede: Java ist vollständig Objektorientiert

  • Objektorientierung bedeutet im wesentlichen:

    Applets: Graphische Java Anwendungen

    Die derzeit wichtigste Anwendung von Java sind graphisch (bzw. musikalisch) aufwendige Programme, die über das World-Wide-Web verbreitet werden können.

    Java-Applets funktionieren wie viele andere GUI-(Graphical User Interface) Packete (z.B. Motif) nach dem "Callback"-Prinzip. Dabei wird im Programm dauernd eine sogenannte "Eventloop" abgearbeitet, bei der auf auftretende Ereignisse ("Events" z.B. Mausklick auf ein bestimmtes Feld oder Fensterneuzeichnen notwendig) reagiert wird. Der Programmierer muß nur festlegen, welche was beim Auftreten dieses Events ausgeführt werden muss.

    In Java wird die Funktion, die festlegt, was beim Auftreten des Events passiert, von der Klasse "Applet" geerbt und über Polymorphie überschrieben. Dadurch gestaltet sich die Programmierung besonders einfach.

    Übung 4:

    Ein einfaches "HelloWorld"-Beispiel, das als Callback für das Neuzeichnen des Fensters implementiert ist, sieht als Applet so aus:

        import java.applet.Applet;
        import java.awt.Graphics;  
       
        // HelloWorldApplet erbt die Funktion paint, die fuer das Neuzeichnen 
        // des Fensters verantwortlich ist
        public class HelloWorldApplet extends Applet
           {
           int redrawcounter=0;
           public void paint(Graphics g)
              {
              g.drawString("Hello world! redraw # "+ ++redrawcounter, 50, 25);
              }
           }
    
    Download HelloWorldApplet.java

    Dieses Programm zählt ausserdem noch die Variable "redrawcounter" pro Fensterneuzeichnen hoch und gibt sie aus.

    Kopieren Sie die folgenden Zeilen in ein File "HelloWorldApplet.java" und compilieren Sie es mit

       javac HelloWorldApplet.java 

    Um das graphische Applet auszuführen, müssen Sie zuerst ein html-File basteln. In diesem File wird über die <Applet> -Anweisung das Javaprogramm eingebunden. Kopieren Sie das folgende html-File als "HelloWorldApplet.html".

         <html>
         <head>
         <title>Hello World</title>
         </head>
         <BODY>
         <applet code="HelloWorldApplet.class" width=300 height=300>
         </applet>
         </html>
    
    Download HelloWorldApplet.html

    Das Javaprogramm kann nun mit

       appletviewer HelloWorldApplet.html 

    oder

       netscape HelloWorldApplet.html 

    gestartet werden.

    Testen Sie, wann ein Neuzeichnen des Fensters nötig wird, indem Sie das netscape/appletviewer iconisieren und wieder aufklappen, ein anderes (kleines) Fenster darüberschieben und wieder wegziehen usw.

    Ein häufiges Dilemma bei GUI-Programmen ist die Tatsache, daß beim Abarbeiten der Eventloop keine eigenen Programmteile ausgeführt werden können und beim Aufruf der Callback -Funktionen die Eventloop gestoppt ist, so daß die graphische Oberfläche "einzufrieren" scheint, weil vom Benutzer veranlasste Events nicht mehr bedient werden können.

    Als Beispiel wird dazu das "Hello World" Applet um einen "sleep"-Aufruf (und das nach Standart nötige Exceptionshandling) ergänzt.

        import java.applet.Applet;
        import java.awt.Graphics;
        import java.lang.*;
    
        // HelloSleepApplet erbt die Funktion paint, die fuer das Neuzeichnen 
        // des Fensters verantwortlich ist
        public class HelloSleepApplet extends Applet
           {
           int redrawcounter=0;
           public void paint(Graphics g)
              {
              try { Thread.currentThread().sleep(5000); } // 5 Sekunden warten
              catch (InterruptedException e) {}          
              g.drawString("Hello world! redraw # "+ ++redrawcounter, 50, 25);
              }
           }
    
    Download HelloSleepApplet.java
    Download HelloSleepApplet.html

    Java besitzt deshalb ein Sprachkonzept, um mehrere Programmstränge gleichzeitig ablaufen zu lassen.

    Um die Ausfuehrung von threads zu ermöglichen, muss der Spezifikation der Appletklasse der Zusatz "implements runnable" und eine "run()"-Funktion sowie eine "start()" und "stop()"-Funktion für den Appletviewer hinzugefügt werden.

    Übung 5:

    Kopieren Sie das folgende Javaapplet und compilieren und starten Sie es. Klicken Sie bei der Ausführung mit der Maus in das Fenster und beobachten Sie die Reaktion.

    /*
        Ein kleineres Beispiel in der Sprache Java
        Das folgende stellt ein sogenanntes Applet dar, ein Programm, das
        ueber das world wide web (www) verteilt werden kann und mit
        html-Browsern wie z.B. netscape oder appletviewer geladen/gestartet 
        werden kann.
        Applets funktionieren wie andere GUI-programmiertools mit der sogenannten 
        Callback-methode.
        Das heisst, dass fuer ein bestimmtes Ereignis (Event z.B. Tastatur, 
        Fensterneuzeichnen noetig, Mausklick usw.) eine damit verbundene Funktion
        aufgerufen wird. Die Verbindung mit diesen Funktionen funktioniert 
        bei Java-Applets ueber Vererbung.
        Ausserdem benutzt dieses Applet die Java Multitasking-Features, damit
        die Callbacks nicht das Abarbeiten von Events (Eventloop) behindert.
    
        Das Programm rechnet in der Initialisierung Daten aus,
        die dann spaeter fuer das Zeichnen auf eine Flaeche benutzt werden
        Ausserdem benutzt sie noch ein paar andere interessante Zeichenfunktionen
     */
    
    // Import von fertigen Java-Klassen/Unterprogrammen
    
    // Grundlegende Appletklasse fuer die Eventloop
    import java.applet.Applet;    
    
    // Alle Klassen des "applet window toolkit"
    import java.awt.*; 
    
    // Mathematische Funktionen
    import java.lang.Math;
     
    
    // Die eigene Klasse erbt mit der Applet-Klasse die Funktion
    // "paint", der Callback fuer das Neuzeichnen des Fensters
    // (ausserdem noch "init" und "start" fuer einen Neustart des Programms)  
    // Die Klasse "runnable" stellt die Funktion "run" fuer Threads zur Verfuegung
    // die unabhaengig von der Applet-eventloop benutzt wird
    
    public class aimBeispiel extends Applet implements Runnable 
      {
    // eigene Daten
    
    // Daten fuer ein gif-bild
      Image gifpicture;
    // Fenstergroesse
      int AppletWidth, AppletHeight;
    // eigene Daten fuer das Zeichnen auf die Flaeche
      int NUM_POINTS = 100;
      int xPoints[][] = new int[NUM_POINTS][2];
      int yPoints[][] = new int[NUM_POINTS][2];
      int xPolygon[] = new int[4];
      int yPolygon[] = new int[4];
      int NUM_ARCS=60;
      int arc=0;
    // Farben fuer das Zeichnen auf die Flaeche
      Color mycolors[] = new Color[NUM_POINTS];
    // Daten fuer die Position des letzten Mausklicks
      int mousex=-1;
      int mousey=-1;
    // Datentyp fuer das Starten/Stoppen eines zweiten Programmtasks
      Thread mytask=null;
    
    // Initialierung
      public void init() 
        {
        double Width1,Height1;
        double Width2,Height2;
        double ElipseWidth,ElipseHeight;
        int i;
        double degree;
        float x,y;
    
    // Daten fuers gifbild einlesen 
        gifpicture=null;
        // getImage ist asynchron, Bild ist erst da vorhanden, wenn gifpicture!=null
        gifpicture = getImage(getDocumentBase(),"maschine.gif");
    // Fenstergroesse und Ellipsengroesse festlegen
        AppletWidth = size().width;
        if (AppletWidth>300)
           ElipseWidth=300; 
        else
           ElipseWidth=AppletWidth; 
        AppletHeight = size().height;
        if (AppletHeight>=100)
           ElipseHeight=100;
        else
           ElipseHeight=AppletHeight;
    // Daten fuer das Zeichnen in "paint" aufbereiten
        // auessere Ellipse
        Width1=ElipseWidth-30;
        Height1=ElipseHeight-30;
        // innere Ellipse
        Width2=ElipseWidth-40;
        Height2=ElipseHeight-40;
    // Punkte fuer Elipsen innerhalb x=-Width1|2...Width1|2 y=-Height1|2...Height1|2
        for (i=0;i<NUM_POINTS;i++)
           {
           // auessere Ellipse
           xPoints[i][0] = (int)((Math.sin((i*2*Math.PI)/NUM_POINTS))*Width1/2.0);
           yPoints[i][0] = (int)((Math.cos((i*2*Math.PI)/NUM_POINTS))*Height1/2.0);
           // innere Ellipse
           xPoints[i][1] = (int)((Math.sin((i*2*Math.PI)/NUM_POINTS))*Width2/2.0);
           yPoints[i][1] = (int)((Math.cos((i*2*Math.PI)/NUM_POINTS))*Height2/2.0);
           }
    // Ellipsen kippen
        for (i=0;i<NUM_POINTS;i++)
           {
           degree=7.0/360.0*2*Math.PI;
           x=xPoints[i][0];
           y=yPoints[i][0];
           xPoints[i][0] = (int)( x*Math.cos(degree)+y*Math.sin(degree));
           yPoints[i][0] = (int)(-x*Math.sin(degree)+y*Math.cos(degree));
           x=xPoints[i][1];
           y=yPoints[i][1];
           xPoints[i][1] = (int)( x*Math.cos(degree)+y*Math.sin(degree));
           yPoints[i][1] = (int)(-x*Math.sin(degree)+y*Math.cos(degree));
           }      
    // Ellipsen in das Fenster verschieben
        for (i=0;i<NUM_POINTS;i++)
           {
           xPoints[i][0] = (int)(xPoints[i][0]+ElipseWidth/2.0);
           yPoints[i][0] = (int)(yPoints[i][0]+ElipseHeight/2.0);
           xPoints[i][1] = (int)(xPoints[i][1]+ElipseWidth/2.0);
           yPoints[i][1] = (int)(yPoints[i][1]+ElipseHeight/2.0);
           }
    // Farben definieren 
        for (i=0;i<NUM_POINTS;i++)
           {
           // RGB-Werte
           mycolors[i]=new Color(255,255,(int)((i*255.0)/(2.0*NUM_POINTS)));
           // Ausgabe der Punkte auf stdout (funktioniert nicht mit netscape)
           // System.out.println("start "+i+" "+xPoints[i][0]+" "+yPoints[i][0]
           //                              +" "+xPoints[i][1]+" "+yPoints[i][1]);
           }
        }
    
    // Start des Applets
      public void start() 
        {
    // Neuen Task starten
        mytask = new Thread(this);
        mytask.start();
    // Fenster neu malen
        repaint();
        }
    
    // Stop des Applets
      public void stop() 
        {
        // diese Zuweisung führt dazu, daß der java-Garbagecollector 
        // den bei start() angeforderten Thread automatisch entsorgt
        mytask = null;
        }
    
    // Starten der Anwendung
     public void run () 
        {
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    // immer wieder Flaeche neuzeichnen, dann warten
        while (true) 
          {
          repaint();
          try 
            {
            Thread.currentThread().sleep(100);
            }
          catch (Exception e) 
            {      
            System.out.println("da war was !");
            }
          }  
        }
    
    // Callback fuer Flaeche neu malen 
      public void paint(Graphics graph) 
        {
        Color mycolor;
    
    // gif-bild malen
       if (gifpicture!=null)
          graph.drawImage(gifpicture,0,60,this); 
    // schwarze Farbe setzen
        graph.setColor(Color.black);
    // line ziehen
       graph.drawLine(arc,arc,arc+22,arc);
    // Text schreiben
        graph.drawString("Java Beispiel",arc,arc);
    // rote Farbe setzen
        graph.setColor(Color.red);
    // Mausklickposition schreiben
        if (mousex>0)
           graph.drawString("Mausklick bei "+mousex+" "+mousey,AppletWidth/2,10);
    // Ellipse malen
        for (int i=arc; i < arc+NUM_ARCS; i++) 
          {
          if (i<NUM_POINTS-1)
             {
             // Farbe setzen
             graph.setColor(mycolors[i]);
             // polygonzug besetzen
             xPolygon[0]=xPoints[i][0];
             xPolygon[1]=xPoints[i][1];
             xPolygon[2]=xPoints[i+1][1];
             xPolygon[3]=xPoints[i+1][0];
             yPolygon[0]=yPoints[i][0];
             yPolygon[1]=yPoints[i][1];
             yPolygon[2]=yPoints[i+1][1];
             yPolygon[3]=yPoints[i+1][0];
             }
          else if (i==NUM_POINTS-1)
             {
             // Farbe setzen
             graph.setColor(mycolors[i]);
             // polygonzug besetzen
             xPolygon[0]=xPoints[i][0];
             xPolygon[1]=xPoints[i][1];
             xPolygon[2]=xPoints[0][1];
             xPolygon[3]=xPoints[0][0];
             yPolygon[0]=yPoints[i][0];
             yPolygon[1]=yPoints[i][1];
             yPolygon[2]=yPoints[0][1];
             yPolygon[3]=yPoints[0][0];
             }
          else
             {
             // Farbe setzen
             graph.setColor(mycolors[i-NUM_POINTS]);
             // polygonzug besetzen
             xPolygon[0]=xPoints[i-NUM_POINTS+1][0];
             xPolygon[1]=xPoints[i-NUM_POINTS+1][1];
             xPolygon[2]=xPoints[i-NUM_POINTS][1];
             xPolygon[3]=xPoints[i-NUM_POINTS][0];
             yPolygon[0]=yPoints[i-NUM_POINTS+1][0];
             yPolygon[1]=yPoints[i-NUM_POINTS+1][1];
             yPolygon[2]=yPoints[i-NUM_POINTS][1];
             yPolygon[3]=yPoints[i-NUM_POINTS][0];
             }
          // Gefuelltes Polygon malen
          graph.fillPolygon(xPolygon,yPolygon,4);
          }
        if (arc<NUM_POINTS)
           arc++;
        else
           arc=0;
        }
    
    // callback fuer das Druecken einer Maustaste
    
      public boolean mouseDown(Event e, int x, int y) 
         {
         mousex=x;
         mousey=y;
         return true;
         }
    
      } 
    

    Download aimBeispiel.java
    Download aimBeispiel.html
    Download Grafikdaten

    Compilieren Sie das Programm mit

       javac aimBeispiel.java 

    Da das Programm fü die Javaversion 1.0 geschrieben wurde (derzeit ist Version 1.2 aktuell), kann es nötig sein, dass Sie gegebenenfalls mit

       javac -deprecation aimBeispiel.java  

    compilieren müssen.

    Nachdem Sie das Programm ausprobiert haben, entfernen Sie aus dem Programm alles was man für Threads braucht.
    Tip: Entfernen sie die Variable "mytask" vom Datentyp "Thread" und alles was zu ihr gehoert.

    Wiederholen Sie das Experiment mit der Maus.

    Schieben Sie auch mal ein anderes Fenster über das Applet und ziehen Sie es wieder weg.

    Kopieren Sie sich das urspüngliche Javaapplet erneut.

    Benutzen Sie es als Basis für eine Programmieraufgabe, bei der Sie ein Java-Applet programmieren, bei dem zumindest die Javafunktion "drawOval" benutzt werden muss.

    Eine Beschreibung der Funktion "drawOval" findet sich in der Beschreibung der "Applet API Packages"

    Suchen Sie nach drawOval

    Tip: Schauen Sie sich mal den Aufruf von "drawString" im Programm etwas genauer an...

    Eine kurze Beschreibung weiterer Events findet sich in:

    Liste von Events

    Um ein Testat für diesen Teil des AIM-Praktikums zu bekommen, schicken Sie bitte Ihr Programm per mail an scheurich@csv.ica.uni-stuttgart.de und vergessen Sie nicht, ihren Namen mit anzugeben.