Usenet.com

www.Usenet.com

Group Index

News Thread Archive from Usenet.com

<-- __Chronological__ --> <-- __Thread__ -->

FAQ der Newsgroup de.comp.lang.java Version 1.34 vom 03.10.2003





Archive-name: de/comp-lang-java/faq
Posting-Frequency: weekly (Friday)
Last-modified: 2003-09-28
Version: 1.34
URL: http://www.dclj.de/, http://de.geocities.com/uweplonus/faq, 
http://www.faqs.org/faqs/de/comp-lang-java/faq, 
ftp://rtfm.mit.edu/pub/faqs/de/comp-lang-java/faq
Expires: 17 Oct 2003 00:00:00 CEST
Tab-Width: 4
Page-Width: 74

  FAQ (Frequently Asked Questions) der Newsgroup de.comp.lang.java v1.34
=========================================================================

Inhalt:
-------

1. Allgemeines

   1.1. Allgemeine Hinweise zum Posten
   1.2. Worum geht es in dieser Newsgroup?
   1.3. Wie kommen häufig gestellte Fragen in diese FAQ?
   1.4. Wie kommen die Bugs aus der FAQ?
   1.5. TAGS-Konventionen zu einem einheitlichen Aussehen
   1.6. Ich bekam als Antwort auf meine Frage eine seltsame Buchstaben-
        kombination zugeschickt. Was ist das und wie kann ich es lesen?


2. Was man über Java wissen sollte

   2.1. Was ist Java?
   2.2. Verwandtschaft von Java mit anderen Sprachen?
   2.3. WebBrowser und Java
   2.4. Erste Schritte in Java
   2.5. Ich habe das HelloWorld-Programm aus meinem Java-Buch 
        abgeschrieben, aber es funktioniert nicht. :-(


3. Häufig gepostete Fragen

    3.1. [LANG] - Die Sprache Java.
        3.1.1. Gibt es in Java keine Zeiger wie in C++?
        3.1.2. Warum ist Referenz nicht gleich Referenz?
        3.1.3. Wie werden in Java Funktionsparamter übergeben, by value
               oder by reference?
        3.1.4. Warum gibt es in Java keine Destruktoren wie in C++?
        3.1.5. Warum funktioniert die equals Methode nicht?
        3.1.6. Wenn ich eigene Objekte mit einer Hashtable/HashMap 
               verwalte, kommt es zu sonderbaren Effekten. Wieso?
        3.1.7. Was bedeutet das Schlüsselwort final?
        3.1.8. Warum wird der dynamische Parametertyp bei überladenen
               Funktionen nicht beachtet?
        3.1.9. Was bedeutet super()?
        3.1.10. Was sind anonyme Arrays?
        3.1.11. Gibt es in Java einen Prä-Prozessor wie in C++?
        3.1.12. Existiert der const Modifizierer von C++ auch in Java?
        3.1.13. Wie kann man Referenzen von Übergabeparametern ändern?
        3.1.14. Wie erzeuge ich eine  tiefe  Kopie eines Objektes mit 
                möglichst wenig Aufwand?
        3.1.15. Wie kann ich in Java eine dem Programmierer unbekannte
                Anzahl gleichartiger Objekte erzeugen und ihnen passende
                Namen zuweisen, also label1, label2 usw.?
        3.1.16. Wie kann ich den Typ enum aus C++ in Java umsetzen?
        3.1.17. Kann man Mehrfachvererbung mit Java simulieren?
        3.1.18. Wie realisiere ich eine variable Parameterliste?
        3.1.19. Wie realisiere ich eine Methodenauswahl nach den 
                dynamischen Parametertypen?
        3.1.20. Sind Methoden in Java immer virtuell?
        3.1.21. Ich stosse ab und zu auf den Begriff "Wrapper-Klassen".
                Könnte mir jemand erklären was das ist? 
        3.1.22. Warum ist private nicht privat?


    3.2. [STRING] - Strings.
        3.2.1. Wie vergleiche ich zwei Strings in Java?
        3.2.2. Wie wandle ich einen String in einen Integer?
        3.2.3. Wie wandle ich einen Integer in einen String um?
        3.2.4. Wie wandle ich einen Integer in einen HexString um?
        3.2.5. Wie kann ich eine Zahl formatieren und wie lege ich die 
               Anzahl der Nachkommastellen fest?
        3.2.6. Wie kann ich ein Datum formatieren?
        3.2.7. Wie kann ich in einem String oder StringBuffer mehrere 
               Zeichen suchen und ersetzen?
        3.2.8. Gibt es reguläre Ausdrücke in Java (regular expressions)? 


    3.3. [IO] - Eingabe/Ausgabe, Streams, etc.
        3.3.1. Verlangsamt Serialisierung mein Programm?
        3.3.2. Wie kann ich rekursiv einen Verzeichnisbaum abarbeiten?
        3.3.3. Wie kann ich aus Dateien zeilenweise lesen?
        3.3.4. Wie kann ich Exponentialzahlen (z.B. 1.09E+008) aus einer
               Datei lesen?
        3.3.5. Wie kann ich mit Java Dateien kopieren?
        3.3.6. Wie kann man auf programmnahe Resourcen (Button-images,
               local String properties,...) zugreifen, ohne absolut oder
               relativ zu user.dir adressieren zu müssen (ich will das 
               ganze auch in ein jar packen können)?


    3.4. [NET] - Netzwerk.
        3.4.1. Wie kann ich einen Ping in Java realisieren?


    3.5. [AWT] - Abstract Window Toolkit.
        3.5.1. Wenn ich einen Listener bei mehreren Buttons anmelde, wie
               kann ich dann unterscheiden, welcher gedrückt wurde?
        3.5.2. Kann ich ein Fenster (Frame/JFrame) maximieren?
        3.5.3. Wie tausche ich die Kaffeetasse im blauen Balken aus?


    3.6. [SWING] - Swing, das bevorzugte GUI.
        3.6.1. Wie mache ich globale Font-Änderung für meine Komponenten?
        3.6.2. Wie kann ich bei der Eingabe in ein JTextField die Anzahl
               der eingebbaren Zeichen beschränken?
        3.6.3. Wie setze ich den Cursor an den Anfang der JTextArea?
        3.6.4. Wie scrolle ich an das Ende der JTextArea?
        3.6.5. Wie bekomme ich es hin, das der Benutzer in meiner JTable
               keine Eingaben tätigen kann?
        3.6.6. Wie bekomme ich eine horizontale ScrollBar bei JTable?
        3.6.7. Wie scrolle ich ans Ende von JTable?
        3.6.8. Wie verhindere ich ein reordering der Spalten bei JTable?
        3.6.9. Wie verhindere ich ein Resizen der Spalten bei JTable?
        3.6.10. Wie ändere ich die Hintergrundfarbe von JScrollPane?
        3.6.11. Wie kann ich ein JLabel dazu bringen, seinen Hintergrund
                zu füllen?

    3.7. [APPLET] - Java-Applets und ihre Zusammenarbeit mit Browsern.
        3.7.1. Welche JDK-Version sollte ich für Applets verwenden, die
               möglichst allgemein lauffähig sein sollen?
        3.7.2. Wie bekomme ich den Internet Explorer dazu, das Plugin 
               anstelle der integrierten JVM zu benutzen.
        3.7.3. Was dürfen unsignierte Applets nicht aus 
               Sicherheitsgründen?


    3.8. [SERVER] - Servlets und andere Server-Implementierungen in Java.


    3.9. [NONCORE] - Klassen/Packages, die über den Kern der Sprache  
                     hinausgehen, also Java3D etc.

    3.10. [OOP] - OOP-Konzepte und Patterns in Java.
        3.10.1. Was bedeutet Vererbung im OO-Kontext?
        3.10.2. Was bedeutet Aggregation im OO-Kontext?
        3.10.3. Was bedeutet Assoziation ist OO-Kontext?
        3.10.4. Was bedeutet Benutzung im OO-Kontext?
        3.10.5. Worin liegen die Unterschiede zwischen abstrakten Klassen
                und Interfaces?
        3.10.6. Was ist eine anonyme innere Klasse?
        3.10.7. Was ist ein immutable Objekt?
        
    
    3.11. [JDK] - Virtuelle Maschinen, alles über JDKs, deren
                  Installation und Verwendung.
        3.11.1. Was ist ein Java Development Kit (JDK)
        3.11.2. Was ist ein Java Runtime Environment (JRE)
        3.11.3. Was ist eine Java Virtual Machine (JVM)
        3.11.4. Wie konfiguriere ich JDK1.3/1.4 unter Linux oder Unix?
        3.11.5. Wie installiere und konfiguriere ich das jdk unter 
                Windows 9x/Me/NT/2000 richtig?




    3.12. [TOOLS] - Java-Zusatz-Tools, zum Beispiel IDEs, Build-Tools, 
                    Profiler, etc.
        3.12.1. Welche IDE muss ich verwenden?
        3.12.2. Wie kann man eine Java-Anwendung in eine EXE-Datei
                umwandeln?


    3.13. [MISC] - Alles, was nicht in eine der anderen Rubriken paßt.
        3.13.1. Warum rechnet Java falsch?
        3.13.2. Wie belege ich ein Array mit einem bestimmten Wert?
        3.13.3. Wie kann ich in Java Zufallszahlen im Bereich 0..n 
                erzeugen?
        3.13.4. Ich komme mit dem import-Statement nicht klar, was mache 
                ich falsch?
        3.13.5. Warum gibt es Probleme bei final Werten in Verbindung mit
                elementaren Typen?
        3.13.6. Was bedeuten "$" im Namen von Class-Files?
        3.13.7. Wie lassen sich Bilder im Dateiformat XYZ laden oder 
                speichern?
        3.13.8. Was geht nicht mit Java?
        3.13.9. Wie kann ich in meinem Java-Programm ein HTML-Dokument
                anzeigen lassen?
        3.13.10. Unter Windows werden in der Konsole (DOS-Eingabe-
                 aufforderung) die Umlaute falsch ausgegeben. Wie kann 
                 ich das korrigieren?



        

    3.14. [ERROR] - Fehlermeldungen.
        3.14.1. Warum findet Java den Konstruktor nicht?
        3.14.2. Warum bekomme ich eine "NoClassDefFoundError" 
                Fehlermeldung beim Starten von java?
        3.14.3. Warum bekomme ich eine "Couldn't read <Name>" 
                Fehlermeldung beim Kompilieren mit javac?
        3.14.4. Warum bekomme ich eine "class <Name> must be defined in
                a file called <Name>" Fehlermeldung  beim Kompilieren 
                von javac?
        3.14.5. Warum wird beim Zugriff auf ein korrekt initialisiertes 
                Objekt-Array eine NullPointerException geworfen?
        3.14.6. Warum bekomme ich eine NullPointerException, wenn ich 
                versuche, auf Methoden oder Attribute von in einem Array
                gespeicherten Objekten zuzugreifen?
        3.14.7. Warum meckert der Compiler bei nicht initialisierten 
                final Variablen?
        3.14.8. Was hat die Compilerfehlermeldung "... is deprecated" zu
                bedeuten?


3.15. [ClassLoader]
        3.15.1 Wie funktionieren Classloader?
        3.15.2 Warum macht der Classloader im Servlet-Container Probleme?
               Warum funktioniert das Einlesen von Ressourcen ueber den 
               Classloader bei mir nicht?
        3.15.3 Wie lade ich eine Klasse neu?
        3.15.4 Wie baue ich einen Plugin-Mechanismus?
        3.15.5 Gibt's dazu auch Beispielcode?



4. Bücher zum Thema Java
    
    4.1. Kann mir jemand gute Literatur zum Thema Java empfehlen?
    

5. Themenverwandte Internet Ressourcen

    5.1 WWW-Sites
    5.2 Newsgroups
    5.3 Mailinglisten


6. JavaScript Internet Ressourcen.

    6.1 WWW-Sites
    6.2 Newsgroups


7. Credits
_____________________________________________________________________

1. Allgemeines
==============

1.1. Allgemeine Hinweise zum Posten
-----------------------------------
Wenn du neu im Usenet bist, solltest du auf jeden Fall die Texte in
der Newsgroup <news:de.newusers.infos> lesen. Du findest sie auch im
WWW auf <URL:http://www.kirchwitz.de/~amk/dni/>. In diesen Texten
erhält man einen Überblick über die im Usenet üblichen Regeln
("Netiquette"). Auf diese Weise lassen sich die meisten Anfänger-
fehler verhindern und man vermeidet, gleich für sein erstes Posting
wegen formaler Fehler angeschnauzt zu werden. Falls du Fragen zu den
Regeln im Usenet hast, stelle sie bitte in der Newsgroup 
<news:de.newusers.questions>.

Weitere Links zum Thema:

    <URL:ftp://rtfm.mit.edu/pub/usenet/de.answers/de-newusers/>
    <URL:http://learn.to/quote/>


1.2. Worum geht es in dieser Newsgroup?
     Autor: Markus Reitz
---------------------------------------
In der Newsgroup <news:de.comp.lang.java> sollen Probleme und Lösungen,
die sich im Zusammenhang mit der Programmiersprache Java ergeben,
diskutiert werden. Die Newsgroup beschäftigt sich nur mit der Sprache
Java! JavaScript oder herstellerspezifische Implementierungen (z.B.
Microsoft J++) besitzen eigene Newsgroups, in denen diese
spezifischen Probleme und Lösungen diskutiert werden. Neben der
Newsgroup <news:de.comp.lang.java> gibt es noch weitere (vor allem
englischsprachige) Newsgroups, die sich mit der Programmiersprache
Java beschäftigen. Siehe auch den Abschnitt "Themenverwandte
Newsgroups".

1.3. Wie kommen häufig gestellte Fragen in diese FAQ?
     Autor: Uwe Günther
-----------------------------------------------------
Nachdem man festgestellt hat, dass man in einem bestimmten Zyklus die 
gleiche Frage immer wieder mit der gleichen Antwort beantworten muss -
nur weil die Unis ihren Lehrplan mal wieder geändert haben, in der c't 
mal wieder ein "Wie programmiere ich ein Applet"-Kurs unter die Leute 
gebracht wurde oder aus welchen Gründen auch immer - sollte man einen 
neuen Thread mit dem 

    Subject: [FAQ] Neue Frage: <Frage>

beginnen.

Der Body dieser Nachricht sollte folgendes Format besitzen:

--Schnipp--
Frage: <Frage>

Antwort: <Antwort>

Beispiel: <Code>
--Schnapp--

Wobei der Text in spitzen Klammern, dein Part ist. Die Zeilenlänge darf 
74 Zeichen nicht überschreiten. Der Code sollte die Code Conventions von
Sun einhalten - wenn du nicht weisst was das ist, solltest du besser 
keine FAQ schreiben. Der gesamte Text darf keine Tabs enthalten und bei 
Bedarf gegen 4 Leerzeichen ersetzt werden. Es ist von grossem Vorteil 
wenn der Beispiel-Code kompilierbar ist. Das steigert die Qualität der 
FAQ ungemein.

Nachdem der Thread dann von den Regulars und den anderen Lesern von
de.comp.lang.java gebührend behandelt wurde und etwaige Probleme 
ausgeräumt wurden, muss die Endfassung des Textes an die im Header dieser
FAQ angegebene e-mail Adresse des FAQ-Maintainers von de.comp.lang.java
gesendet werden. Dabei ist es erwünscht die Rubrik, oder gleich die 
zukünftige Fragennummerierung mit anzugeben. Weiterhin muss die 
Message-ID mit angegeben werden, damit der FAQ-Maintainer überprüfen kann
ob er nicht von irgendjemanden vereimert wird. ;-)


1.4. Wie kommen die Bugs aus der FAQ?
     Autor: Uwe Günther
-------------------------------------
Nachdem man festgestellt hat, dass die FAQ einen Fehler hat, kann man 
diesen dem FAQ-Maintainer unter Angabe eines Workarounds direkt 
mitteilen.


1.5. TAGS-Konventionen zu einem einheitlichen Aussehen
     Autor: Markus Reitz
--------------------------------------------------------
Neben den schon weiter oben genannten Ratschlägen, die allgemeine
Anmerkungen zum Posten in Newsgroups darstellen, folgen nun einige
spezifische Anmerkungen zur Schreibweise des Subjects in der
Newsgroup <news:de.comp.lang.java>. Vor einiger Zeit wurde die
Einführung sogenannter Tags vorgeschlagen, die die Übersichtlichkeit
steigern sollen. Hintergrund ist die einfache Idee, den Inhalt des
Postings durch ein eindeutiges Schlüsselwort, das Tag, zu
charakterisieren. Mit einem entsprechend konfigurierten Newsreader ist
es dann möglich, sich solche Nachrichten hervorheben zu lassen, wodurch
man direkt auf einen Blick Postings beispielsweise zum Thema Swing
überschauen kann. Tags werden an den Anfang des Subjects, in eckigen
Klammern eingeschlossen, geschrieben. Damit Einheitlichkeit gewahrt
wird, sollten die folgenden Tags verwendet werden. Wenn jeder seine
eigenen Tags spezifizieren würde, wäre die Einheitlichkeit verloren und
es würde genau-soviel Chaos wie vorher herrschen. Deshalb an dieser
Stelle die Bitte, sich an die Vorgaben zu halten. Bei
Änderungsvorschlägen bitte in die Newsgroup zur Diskussion posten und
bei Akzeptanz in der Newsgroup werden die Vorschläge an dieser Stelle
in die FAQ aufgenommen.

Liste der Tags in <news:de.comp.lang.java>:

Tags für Fragen:

    [LANG]
    - Frage bezüglich der Sprache Java.
    
    [STRING] 
    - Fragen die unmittelbar mit Strings zu tun haben.
    
    [IO] 
    - Frage bezüglich Eingabe/Ausgabe, Streams, etc. in Java.
    
    [NET]
    - Frage bezüglich Netzwerk.
    
    [AWT]
    - Frage bezüglich AWT.
    
    [SWING]
    - Frage bezüglich Swing.
    
    [APPLET]
    - Frage zu Java-Applets und ihre Zusammenarbeit mit Browsern.
    
    [SERVER] 
    - Frage zu Servlets und anderen Server-Implementierungen in Java.
    
    [NONCORE]
    - Fragen zu Klassen/Packages, die über den Kern der Sprache  
      hinausgehen, also Java3D etc.

    [OOP] 
    - Frage bezüglich OOP-Konzepten und Patterns in Java.
    
    [JDK]
    - Frage zu virtuelle Maschinen, alles über JDKs und deren
      Installation und Verwendung.
    
    [TOOLS]
    - Frage zu einem Java-Zusatz-Tool, zum Beispiel IDEs, Build-Tools,
      Profiler, etc.

    [MISC]
    - Alles, was nicht in eine der anderen Rubriken paßt.
    
    [ERROR] 
    - Fragen zu Fehlermeldungen.
    
    [OT]
    - Alles was hochgrading off-topic ist und nicht direct mit Java zu 
      tun hat. ;-)


Tags "nicht"-Fragen:

    [INFO]
    - Allgemeine Informationen, z.B. Links auf Webseiten

    [DISCUSSION]
    - Diskussion zu einem Java-spezifischen Thema

    [ANNOUNCE]
    - Vorstellung neuer Software

    [PROST]
    - Darf nur von Regulars verwendet werden, die wissen was sie tun. ;-)


1.6. Ich bekam als Antwort auf meine Frage eine seltsame Buchstaben-
     kombination zugeschickt. Was ist das und wie kann ich es lesen?
     Autor: Stephan Menzel
--------------------------------------------------------------------
Diese Kombination ist eine sogenannte Message-ID und bezeichnet einen
Usenetartikel eindeutig.
 
Vorgehensweise bei Message-ID-Angaben:

(a) man hat einen Newsreader, der damit umgehen kann:
    - einfach draufklicken.

(b) Wenn man Opera ab Version 6 verwendet, kann man in der Adressleiste
einfach "r msgid:[EMAIL PROTECTED]" eingeben und gelangt
zur entsprechenden Seite von Google Groups.

(c) ansonsten: http://groups.google.com, 
dann msgid:[EMAIL PROTECTED] eingeben.

(d) Wenn man gerne URLs bastelt:
http://groups.google.com/groups?q=msgid:[EMAIL PROTECTED]

(e) oder http://groups.google.com/advanced_group_search dann Msg-ID bei
"Beitrags-ID" eingeben.



2. Was man über Java wissen sollte
==================================

2.1. Was ist Java
     Autor: Markus Reitz
------------------------
Zuersteinmal: Java ist nicht JavaScript. JavaScript ist eine Sprache,
die federführend von der Firma Netscape entwickelt wurde, um die
Inhalte von Webseiten dynamischer und interaktiver zu gestalten.
JavaScript-Programme werden in den HTML-Quelltext der Seite
eingebettet und vom Browser interpretiert und ausgeführt. Zwar macht
JavaScript viele Anleihen bei Java, ist aber bei weitem nicht so
flexibel.

    Die deutsche Newsgroup zu JavaScript findet man unter:

        <news:de.comp.lang.javascript>

    Die Website von de.comp.lang.javascript ist unter folgendem
    Link zu finden:

        <URL:http://www.dcljs.de/>

Java wurde von der Firma SUN Microsystems mit dem Ziel entwickelt, eine
moderne, objektorientierte Sprache zu schaffen. Durch das Ziel der
Plattformunabhängigkeit ist Java vor allem im Zusammenhang mit der
Entwicklung von Web-Applikationen im Internet eine der am häufigsten
verwendeten Sprachen. Doch Java beschränkt sich nicht nur auf das
Erstellen von Effekten für die Webseite, Java ist eine ausgewachsene
Programmiersprache, mit der man alle anstehenden Probleme lösen kann.
Die Syntax der Sprache ist an die von C++ angelehnt, Schlüsselwörter
sind verändert bzw. in der Bedeutung erweitert worden, bestimmte
Features von C++ wurden zugunsten der Übersichtlichkeit bzw. Sicherheit
nicht in Java verwendet. Java Programme liegen im sogenannten Bytecode
vor, der Maschinencode für einen fiktiven Prozessor, der von der VM, der
virtuellen Maschine, ausgeführt wird. Durch die Verwendung des Bytecodes
wird die Plattformunabhängigkeit von Java garantiert - dieser Vorteil
wird aber durch die, im Vergleich zu anderen Sprachen wie C++, wesentlich
langsamere Ausführungsgeschwindigkeit bezahlt.


2.2. Verwandtschaft von Java mit anderen Sprachen?
     Autor: Markus Reitz
-------------------------------------------------
Java bietet eine Reihe von neuen Features, orientiert sich aber auch
an etablierten Sprachen wie C++, Smalltalk oder Objective-C.
Prinzipien aus diesen Sprachen wurden übernommen und teilweise
erweitert. Die folgende Tabelle gibt einen kleinen Überblick über
Features von Java, die aus anderen Sprachen quasi "entliehen" wurden.

                                 |-----|-----------|-------------|
                                 | C++ | Smalltalk | Objective-C |
|--------------------------------|-----|-----------|-------------|
| Primitive Datentypen           |  *  |           |             |
|--------------------------------|-----|-----------|-------------|
| Universelle Basisklasse Object |     |     *     |             |
|--------------------------------|-----|-----------|-------------|
| Garbage Collection             |     |     *     |             |
|--------------------------------|-----|-----------|-------------|
| Konstruktoren                  |  *  |           |             |
|--------------------------------|-----|-----------|-------------|
| Statische Typen                |  *  |           |             |
|--------------------------------|-----|-----------|-------------|
| Bibliothek von Standardklassen |     |     *     |             |
|--------------------------------|-----|-----------|-------------|
| Interfaces                     |     |           |      *      |
|--------------------------------|-----|-----------|-------------|

Im Vergleich zu C++ besitzt Java folgende Unterschiede:

  - noch keine Templates
  - keine Operatorenüberladung
  - kein prozeduraler Overhead
  - keine Mehrfachvererbung von Klassen


2.3. WebBrowser und Java
     Autor: Markus Reitz
------------------------
Java zählt immer noch zu den  jüngeren  Programmiersprachen und die
Entwicklung verläuft in manchen Bereichen noch mit hoher
Geschwindigkeit. Insbesondere Zusatz-APIs findet man inzwischen wie
Sand am Meer und praktisch jede neue Version des JDK bietet
Verbesserungen oder Erweiterungen der bestehenden APIs.

Dies wird insbesondere dann problematisch, wenn man Java-Applets
schreiben möchte, die in den bekannten Web-Browsern von Netscape oder
Microsoft laufen sollen. Häufig werden aktuelle Features nur
unzureichend oder gar nicht unterstützt. Deshalb sollte man folgendes
beachten:

  - Ältere Webbrowser unterstützen (im günstigsten Fall) nur die
    Version 1.0 der Sprache
  - Neuere Webbrowser unterstützen zumindest teilweise die
    Sprachversion 1.1 (Netscape ab Version 4.04-J2, Microsoft
    Internet-Explorer ab Version 4.0)

Um eine möglichst große Anzahl an Plattformen bedienen zu können, muß
man sich also am besten auf Features der Sprache beschränken, die schon
in der UrVersion vorhanden waren. Bei neueren Features läuft man
Gefahr, daß Besitzer älterer Browser ausgeschlossen werden. Eine andere
Alternative bietet die Verwendung des von SUN erhältlichen
Java-Plug-In's. Dadurch werden ältere Browserversionen mit den Features
der aktuellen Java-Version aufgerüstet, wodurch es dann sogar möglich
wird, Java 2 - Programme in Browsern ablaufen zu lassen, obwohl diese
die neueste Version ursprünglich noch gar nicht unterstützen. Das
Plug-In ist auf der Homepage von SUN erhältlich, problematisch ist
allerdings die Größe. Es ist daher fraglich, ob Benutzer bereit sind,
sich wegen eines kleinen Homepage-Effektes ein großes Plug-In
herunterzuladen. Sinn macht das Plug-In daher nur bei wirklich größeren
Programmen oder bei Programmen, die für den Einsatz im Intranet
ausgerichtet sind.


2.4. Erste Schritte in Java
     Autor: Markus Reitz
---------------------------
Erfahrungen mit der Sprache Java zu sammeln ist nicht schwer. Sofern
man einen Internetzugang hat, kann man sich die Sprachdefinition,
Compiler etc. direkt von SUN besorgen. Es empfiehlt sich die Verwendung
der Java-Implementierung von SUN, denn diese ist die Referenz für alle
anderen Implementierungen und normalerweise die, die sich am aktuellsten
Sprachstandard orientiert. Lösungen von Microsoft oder Symantec haben
den Nachteil, daß Features modifiziert oder gar nicht implementiert
werden oder Fähigkeiten hinzukommen, die der ursprünglichen
Sprachimplementation fehlen. Außerdem bietet das JDK (Java Development
Kit) von SUN den Vorteil, daß es kostenlos verfügbar ist. Nachteil:
Compiler und Tools arbeiten kommandozeilenorientiert, d.h. man schreibt
den Quellcode mit einem beliebigen Editor, speichert die Datei und führt
dann den Compiler aus. Bei Fehlern lädt man die Datei, korrigiert den
Fehler und das ganze Spiel beginnt von vorne. Abhilfe schaffen IDEs
(Integrated Development Environment), die das JDK steuern und Fehler
und andere Meldungen direkt anzeigen, ohne daß der Quelltexteditor
verlassen werden muß. Ein weiterer Vorteil von IDEs ist das Feature
Syntax Highlighting, das die Schlüsselwörter der Sprache farblich
hervorhebt und dadurch die Übersichtlichkeit steigert.

Bezugsquelle für das JDK: <URL:http://www.java.sun.com/j2se/>


2.5. Ich habe das HelloWorld-Programm aus meinem Java-Buch 
     abgeschrieben, aber es funktioniert nicht. :-(
     Autor: Hubert Partl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Newbie:
Ich habe das HelloWorld-Programm aus meinem Java-Buch abgeschrieben,
aber es funktioniert nicht. :-(

Oldie:
Das ist schon richtig :-) so, das HelloWorld-Beispiel dient dazu,
dass Du die typischen Anfaenger-Fehler kennenlernst und in Zukunft
vermeiden kannst.

In diesem Fall kann ich nur raten: Du hast wahrscheinlich einen der
folgenden typischen Newbie-Fehler gemacht:

* Du hast das Programm nicht genau genug abgeschrieben (Tippfehler,
Gross-Kleinschreibung, Sonderzeichen, Leerstellen), lies doch die
Fehlermeldungen und Korrekturhinweise, die der Compiler Dir gibt.


* Du hast das Programm nicht unter dem richtigen Filenamen abgespeichert.
Wenn die Klasse HelloWorld heisst, muss das File HelloWorld.java heissen,
nicht helloworld.java und auch nicht HelloWorld.java.txt, im letzteren
Fall versuch es mit

    notepad "HelloWorld.java"


* Du hast beim Compiler nicht den kompletten Filenamen mit der Extension
angegeben (wieder mit der richtigen Gross-Kleinschreibung):

   javac HelloWorld.java


* Du hast bei der Ausfuehrung nicht den Klassennamen ohne die Extension
angegeben (wieder mit der richtigen Gross-Kleinschreibung):

    java HelloWorld


* In der Umgebungsvariable PATH ist das Directory, in dem sich die
JDK-Software befindet, nicht neben den anderen Software-Directories
enthalten, versuch
  
    set PATH=%PATH%;C:\jdk1.2\bin

oder wie immer das auf Deinem Rechner heissen muss.


* Die Umgebungsvariable CLASSPATH ist (auf einen falschen Wert) gesetzt.
Diese Variable sollte ueberhaupt nicht gesetzt sein, nur in seltenen
Spezialfaellen und dann so, dass sie sowohl die Stellen enthaelt,
wo die Java-Klassenbibliotheken liegen, als auch den Punkt fuer das
jeweils aktuelle Directory.


* Du hast den Compiler nicht in dem Directory bzw. Folder aufgerufen,
in dem Du das Java-File gespeichert hast.


* Du hast ein Applet als Applikation aufgerufen, oder umgekehrt.
Applikatonen, die eine main-Methode enthalten, musst Du mit

    java Classname

aufrufen. Applets, die ein "extends Applet" oder "extends JApplet"
enthalten, musst Du innerhalb eines geeigneten HTML-Files mit

    appletviewer xxxxx.html

oder mit Netscape oder Internet-Explorer aufrufen.


Mehr darueber findest Du in meiner Java-Einfuehrung auf
    
    <URL:http://www.boku.ac.at/javaeinf/jein1.html#software>


Aehnliche Hinweise findest Du im Java Glossary von Roedy Green auf

    <URL:http://mindprod.com/gloss.html>



3. Häufig gepostete Fragen
==========================


3.1. [LANG] - Frage bezüglich der Sprache Java.
-----------------------------------------------

3.1.1. Gibt es in Java keine Zeiger wie in C++?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Im Prinzip gibt es ein Konstrukt, das den Zeigern anderer 
Programmiersprachen, wie zum Beispiel C++, sehr ähnlich ist: die 
sogenannten Referenzen. Referenzen können, im Vergleich zu Zeigern in
C++, nicht manipuliert werden; die sogenannte Zeigerarithmetik, bei der
man Zeiger auf beliebige Speicherinhalte zeigen lassen kann, wurde aus 
Sicherheitsgründen nicht in Java übernommen. Der Inhalt einer Referenz 
kann einer anderen Referenz zugewiesen werden, Referenzen können 
miteinander verglichen werden. Wird in Java eine Objektvariable 
angelegt, so ist dies nichts weiter als ein Speicherplatz für eine 
Referenz für ein Objekt des angegebenen Typs. Der new-Operator erzeugt 
das eigentliche Objekt und liefert die Referenz darauf zurück, die dann
in der Objektvariablen gespeichert wird.


3.1.2. Warum ist Referenz nicht gleich Referenz?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Problem:

public class Test {
    public static void main (String[] args) {
        String a = "A";
        String x = a;
        System.out.println(x);
        a = "B";
        System.out.println(x);
    }
}

Die Ausgabe sollte doch eigentlich so aussehen:

    A
    B

Denn die Variable x speichert doch eine Referenc auf den String a! Im 
ersten Fall hat a den Wert  A  und damit auch x, das ja auf diesen
String verweist. Im zweiten Fall wird a geändert und damit müßte sich
doch auch eigentlich der Wert von x ändern, weil x auf a verweist. 
Die Ausgabe, die das Programm liefert, ist jedoch:

    A
    A

was eigentlich nicht in das Bild einer normalen Referenz passt.


Ursache:

Der Fehler liegt darin begründet, daß a nicht der eigentliche String
ist, sondern nur eine Referenz auf diesen String. Durch x = a 
referenzieren beide Variablen den selben String und durch a = "B" 
verweist a auf einen anderen neuen String mit dem Wert B. Dies ändert
jedoch nichts an der Referenz, die in x gespeichert ist. Somit ist die
Ausgabe völlig korrekt.



3.1.3. Wie werden in Java Funktionsparamter übergeben, by value 
       oder by reference?
       Autor: Paul Ebermann
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java kennt  (genauso wie C, aber im Gegensatz zu etwa Pascal) kein 
"Call by Reference". Wenn Objekte als Parameter verwendet werden, wird 
eben die Referenz "by Value" übergeben. Somit kann man zwar das Objekt
(so es veränderbar ist) verändern, aber nicht die originale Variable, 
die als Parameter verwendet wurde.

Beispiel für Call by Reference:
(Pascal - [Syntax bestimmt nicht korrekt])

program ReferenzTest(input, output);

  var
  x, y : integer;

  procedure swap (var a: integer; var b: integer);
    var
    h : Integer;

  begin
    h := a;
    a := b;
    b := h;
  end;

begin
  x := 1;
  y := 2;
  swap(x,y);
  writeLn('x = ', x, ', y = ', y , '.');
end.

Das Programm gibt am Ende x = 2 und y = 1 aus.
In Java geht das nicht:

package de.dclj.faq;
class CallByReferenceTest
{
    static void swap (int a, int b)
    {
        int h = a;
        a = b;
        b = h;
    }

    public static void main(String[] test)
    {
        int x = 1;
        int y = 2;
        swap(x,y);
        System.out.println("x = " + x + ", y = " + y);
    }
}

Zur Call-by-Reference-Simulation bietet sich
die Verwendung von Arrays an - da diese Objekte sind,
wird ja nur die Referenz übergeben.


class CallByReferenceSimulation
{
    static void swap(int[] a, int[] b)
    {
        int h = a[0];
        a[0] = b[0];
        b[0] = h;
    }

    public static void main(String[] test)
    {
        int[] x = {1};
        int[] y = {2};
        swap(x,y);
        System.out.println("x = " + x[0] + ", y = " + y[0]);
    }
}

Es gibt auch eine englisch sprachige Web-Site zu diesm Thema:

<http://purl.net/stefan_ram/pub/java_referenzvariablen_als_argument_de>


3.1.4. Warum gibt es in Java keine Destruktoren wie in C++?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Java hat der Programmierer unter normalen Umständen keinen direkten
Einfluß darauf, wann Objekte aus dem Speicher entfernt werden. So ist 
es unter anderem nicht möglich, ein Objekt per Befehl aus dem Speicher 
zu löschen. Dies erledigt der sogenannte Garbage-Collector, der Objekte
aus dem Speicher entfernt, auf die keine Referenz mehr verweist. 
Dadurch wird verhindert, daß der Programmierer mehr oder minder 
mutwillig Speicherfehler erzeugen kann, die das Programm zum Absturz 
bringen könnten. Wann die Entfernung aus dem Speicher erfolgt, liegt im
Ermessen des Computers. Es gibt also keinen definierten Zeitpunkt, wann
ein Objekt nicht mehr existiert und deshalb ist es in den meisten Fällen
nicht sinnvoll, Operationen zu definieren, die beim Löschen des 
Objektes ausgeführt werden. Man könnte (ungültige) Annahmen voraussetzen
- zum Beispiel bei verketteten Listen, daß das Nachfolgerelement noch 
existiert, obwohl dies gar nicht der Fall ist - und damit Fehler 
verursachen. Destruktoren wie in C++ existieren deshalb nicht. Ist es 
aus irgendeinem dringenden Grund dennoch nötig, Operationen beim Löschen
des Objektes auszuführen, so kann man eine Methode finalize definieren, 
die bei der Speicherbereinigung abgearbeitet wird. Wobei nicht garantiert
wird die finalize methode überhaupt von der JVM abgearbeitet wird.

   
3.1.5. Warum funktioniert die equals Methode nicht?
       Autor: Markus Reitz
       Autor: Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Problem 1:

Man hat eine eigene Klasse entworfen und möchte nun testen, ob zwei 
Objekte gleich sind. Fein, denkt man sich, dafür bietet die Klasse 
Object ja die Methode equals(Object obj). Doch das Programm mit 
Verwendung der equals(Object obj) Methode wird zwar korrekt übersetzt, 
der Vergleich funktioniert jedoch nicht so, wie er eigentlich sollte. 

Per Default sagt equals(), dass es sich um die selbe Instanz einer
Klasse handelt:

public class Object {
    ...

    public boolean equals(Object other) {
        return this == other;
    }
 
    ...
}

Lösung 1:

Die Methode equals(Object obj) muß für jede Klasse neu überschrieben 
werden. Schließlich kann man nicht in allgemeiner Weise die Gleichheit
zweier Objekte einer Klasse spezifizieren. Das ist insbesondere dann 
wichtig falls die Objekte in einer Set oder als Keys für eine Map 
verwendet werden. Dann muss allerdings auch die Methode hashCode() 
überschrieben werden.  Siehe dazu auch die nächste Frage in dieser FAQ!

Dazu sollte man sich auf alle Fälle in der JavaDoc zu Object, speziell
die Methoden hashCode() und equals(Object obj) ansehen:

    <URL:http://java.sun.com/j2se/1.4/docs/api/java/lang/Object.html>

Für Strings beispielsweise sind equals() und hashCode() bereits 
überschrieben. So dass String-Objekte als Keys verwandt werden können.


Problem 2:

public class Test {

    private int a;
    private int b;

    public Test (int a , int b) {
        this.a = a;
        this.b = b;
    }

    public boolean equals(Test other) {
        return (this.a == other.a) && (this.b == other.b);
    }
}

Verwendet man nun Objekte dieser Klasse in Containerklassen und hier
insbesondere Methoden, die auf die Methode equals des Objekts 
zurückgreifen, so funktioniert dies nicht. Der Grund liegt in der 
falschen Signatur der Methode equals. Der Parameter muß vom Typ Object
sein und nicht vom Typ der Klasse, zu dem die Methode gehört. Ansonsten
existieren für die Klasse Test zwei Versionen der equals Methode: Eine,
die von der Klasse Object geerbt wurde und die als Parametertyp auch 
Object besitzt und als zweite die oben definierte. Containerklassen 
verwenden aber die erste und da diese nicht verändert wurde, wird nicht
das gewünschte Ergebnis erzielt.

Lösung 2:

public class Test {

    private int a;
    private int b;

    public void Test (int a , int b) {
        this.a = a;
        this.b = b;
    }

    //Die hash-Funktion ist aus dem Buch "Effective Java" von
    //Joshua Bloch.
    public int hashCode() {
        int result = 17;
        result = 37*result + this.a;
        result = 37*result + this.b;
        return result;
    }

    public boolean equals(Object obj) {
        //Für eine bessere Performance.
        if (this == obj) {
            return true;
        } 
        //Wenn (obj == null) dann gibt instanceof false zurück
        //Siehe JLS 15.20.2
        if (!(obj instanceof Test)) {
            return false;
        }
        Test other = (Test)obj;
        return (this.a == other.a) && (this.b == other.b);
    }
}


3.1.6. Wenn ich eigene Objekte mit einer Hashtable/HashMap verwalte, 
       kommt es zu sonderbaren Effekten. Wieso?
       Autor: Ingo R. Homann, Gerhard Bloch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Damit eigene Objekte als Schluessel in einer Hashtable/HashMap
funktionieren, muessen zwei Bedingungen erfuellt sein:

1. Wenn man die equals-Methode einer Klasse überschreibt, sollte man
   beachten, dass man auch die hashCode-Methode überschreiben muß!
2. Nichts, was equals-Vergleiche beeinflusst, darf geaendert werden,
   waehrend das Objekt in einer Hashtable/HashMap ist! Insbesondere darf
   sich der Hashcode nicht aendern.

Man muss sicherstellen, dass Objekte, die laut der equals-Methode gleich
sind, auch einen identischen Hashcode haben müssen. Der Umkehr-Schluss,
dass ungleiche Objekte (bei denen equals false liefert) zwangsläufig
auch unterschiedliche Hashcodes haben müßen, gilt nicht. Trotzdem sollte
man als Programmierer versuchen, möglichst darauf hinzuarbeiten (und
keineswegs z.B. für alle Objekte einen gleichen, konstanten Hashcode
liefern!), damit die Implementierungen von Hashtable und HashMap
effizient arbeiten können.

Als Folge dieser Forderung sollten zur Berechnung des Hashcode genau die
Attributwerte einbezogen werden, die auch zur equals-Bestimmung
verwendet werden, insbesondere aber keine anderen Werte!

Die Forderung kann auch so formuliert werden:
        a.equals(b) => (a.hashCode() == b.hashCode())
oder    (a.hashCode() != b.hashCode()) => !a.equals(b)


Eine Hashtable funktioniert vereinfacht folgendermassen:
Die Schluessel-Wert-Paare werden beim Einfuegen in Buckets ("Eimer")
verteilt. Dabei entscheidet der Hashcode des Schluessels, in welchen
Bucket er kommt.
Beim Suchen wird anhand des Hashcodes des Suchschluessels der Bucket
ermittelt, in dem das gesuchte Objekt liegen muss. So können (außer
in ungünstigen Fällen) fast alle Schluessel der Tabelle ausgeschlossen
werden, der Suchschluessel muss nur noch innerhalb des Buckets gesucht
werden; falls er (genauer: ein Schluessel, dessen equals-Vergleich mit
dem Suchschluessel true ergibt) dort gefunden wird , wird der Wert
zurueckgegeben.
Dies funktioniert deshalb, weil aufgrund der obigen Forderung nur
diejenigen Objekte uebereinstimmen koennen, die auch im Hashcode
uebereinstimmen (equals => gleicher Hashcode).

Ein Problem ergibt sich, wenn nach dem Einfuegen ein Schluessel
geaendert wird. Da sich dadurch auch dessen Hashcode (mit ziemlicher
Sicherheit) aendert, liegt er nun im falschen Bucket. Die Hashtable
bekommt von der Aenderung ja nichts mit!
Deshalb ist zu beachten, dass sich Schluessel nicht aendern, solange sie
in einer Hashtable verwendet werden. Sichergestellt werden kann dies nur
durch immutalbe Objekte (siehe 3.10.7).

Beispiel fuer das richtige Ueberschreiben von hashCode:

public class Name {
    private static int zaehler= 0;

    private String     vorname
    private String     nachname;
    private final int  id = zaehler++;

    public Name(String vorname, String nachname) {
        this.vorname = vorname;
        this.nachname = nachname;
    }

    public boolean equals(Object o) {
        // die id ist nur fuer interne Zwecke und hat keinen Einfluss
        // auf Gleichheit
        if(o instanceof Name) {
            Name n = (Name)o;
            return vorname.equals(n.vorname) && 
                   nachname.equals(n.nachname);
        } else {
            return false;
        }
    }

    public int hashCode() {
        // Es werden genau die Werte einbezogen, die auch in der
        // equals-Methode verwendet werden
        int result = 17;
        result = 37*result + vorname.hashCode();
        result = 37*result + nachname.hashCode();
        return result;
    }
}


3.1.7. Was bedeutet das Schlüsselwort final?
       Orginalautor: Markus Reitz
       Autor: Paul Ebermann
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Klassen oder Methoden, die das Schlüsselwort final tragen, können nicht
mehr überschrieben werden, wenn von dieser Klasse abgeleitet wird. Die
Verwendung dieses Schlüsselwortes bietet sich aus zwei Gründen an:

  - Realisierung von Sicherheitsmaßnahmen
  - Codeoptimierung

Sicherheitsmaßnahmen werden realisiert, weil es nicht möglich ist, die
Bedeutung der Methode in abgeleiteten Klassen zu verändern und damit 
bestehende Konzepte zu durchbrechen. Codeoptimierung deshalb, weil der
Compiler nun davon ausgehen kann, daß sich an den Methoden nichts mehr 
ändern wird und deshalb elegantere Codeoptimierungen möglich sind. In 
Anbetracht der Tatsache, daß final-Methoden nicht mehr verändert werden
können, muß man sich beim Programmentwurf sehr sicher sein, daß das 
Feature des Überschreibens definitiv nicht für diese Methode benötigt 
wird, ansonsten kann es bei Verbesserungen des Codes zu Problemen 
kommen.

Wenn Variablen mit dem Schlüsselwort final deklariert werden, hat das 
zur Folge, dass ihr Wert nur einmal zugewiesen (initialisiert) und dann 
nicht mehr verändert werden kann. Wenn der Compiler das nicht nachweisen
kann, gibt es einen Fehler.

* Bei Exemplarvariablen kann die Zuweisung direkt in der Deklaration, in
einem Initialisierungsblock oder in (dann allen) Konstruktoren erfolgen.
Bei Klassenvariablen kann die Zuweisung direkt in der Deklaration oder
in einem Klassen-Initialisierungsblock erfolgen.

* Bei lokalen Variablen muss die Zuweisung in der Deklaration oder 
irgendwo später im Code, jedenfalls vor dem ersten Lese-Zugriff erfolgen.

* Bei Methoden- oder Konstruktor-Parametern mit final kann keine 
Zuweisung erfolgen.


3.1.8. Warum wird der dynamische Parametertyp bei überladenen 
       Funktionen nicht beachtet?
       Autor: Uwe Günther, Erwin Hoffmann, Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dies ist ein korrektes Verhalten gemäß der Java-Sprachspezifikation! 

Die Entscheidung, welche überladene Methode bei der Übergabe eines 
bestimmten Parameters auszuwählen ist, wird nicht anhand des Typs des 
an die Methode übergebenen Objekts getroffen, sondern anhand des Typs 
der Referenz, die auf das übergebene Objekt verweist.
Diese Entscheidung wird vom Compiler getroffen. Hier muss also zur 
Compilezeit entschieden werden, welche Methode aufgerufen werden soll.
Der Compiler kann sich nur auf den Referenztyp beziehen, weil der 
Objekttyp nur dynamisch zur Laufzeit eines Programms festgestellt werden
kann.

Das Ganze demonstriert ein Beispielprogramm:

public class BasisKlasse {}

public class AbgeleiteteKlasse extends BasisKlasse {}

public class Test {
    public static void methode(BasisKlasse eineKlasse) {
        System.out.println("Methode mit BasisKlasse!");
    }

    public static void methode(AbgeleiteteKlasse eineKlasse) {
        System.out.println("Methode mit AbgeleiteteKlasse!");
    }
    
    public static void testMethode(BasisKlasse a) {
        if (a instanceof AbgeleiteteKlasse) {
            System.out.print("Abgeleitet: ");
        } else {
            System.out.print("Basis: ");
        }

        //Welche Methode wird jetzt gerufen?
        methode(a);
    }
    
    public static void main (String[] params) {
        BasisKlasse a = new BasisKlasse();
        AbgeleiteteKlasse b = new AbgeleiteteKlasse();
        testMethode(a);
        testMethode(b);
    }
}

Das Programm erzeugt folgende Ausgabe:

    Basis: Methode mit BasisKlasse!
    Abgeleitet: Methode mit BasisKlasse!


3.1.9. Was bedeutet super()?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Werden Ableitungen von Klassen gebildet und dabei Funktionen redefiniert
(überschrieben), so ist es in vielen Fällen nötig, auf die 
Funktionalität der Basisklasse zurückzugreifen. Mit super.methode() 
teilt man mit, daß man die Methode der Basisklasse und nicht die 
Methode der aktuellen Klasse benutzen will. Innerhalb eines 
Konstruktors ist es möglich mit super() den Konstruktor der Basisklasse
aufzurufen. Findet im Konstruktor kein expliziter Aufruf mit super() 
statt, so wird automatisch der parameterlose Konstruktor 
(Standardkonstruktor) der Basisklasse aufgerufen.


3.1.10. Was sind anonyme Arrays?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ab Java 1.1 ist folgender Code gültig:

int i[];
i = new int[] {1, 2, 3};

Es ist jetzt also möglich, Arrays auch außerhalb der Definition mit den
gewünschten Werten zu initialisieren, indem man mit {...} einfach die 
Werte angibt, die das neue Array tragen soll.


3.1.11. Gibt es in Java einen Prä-Prozessor wie in C++?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Nein. In C++ existiert der sogenannte Prä-Prozessor, der es mit
bestimmten Kommandos erlaubt, Teile des Codes zu übersetzen und andere
Teile bei der Übersetzung zu überspringen. Unter Umständen wäre es 
hilfreich, wenn auch Java eine solche Möglichkeit der 
Compilationssteuerung zulassen würde, doch einen Prä-Prozessor gibt es 
hier nicht. Man kann dies aber, zumindest ansatzweise, mit if-Statements
nachbilden. Dazu definiert man eine boolesche Variable DEBUG und in 
Abhängigkeit von dieser Variablen sollen bestimmte Codeteile ausgeführt
werden, andere dagegen nicht.

public class Test {
    final static boolean DEBUG = true;

    public static void main (String[] params) {
        int i = 12;
        if (DEBUG) {
            System.out.println("Der Wert von i ist " + i);
        }
    }
}

Verwendet man nun noch Optimierer, die unbenutzten Code aus den 
Klassendateien entfernen, so hat man im Prinzip ein ähnliches Verhalten
wie beim Prä-Prozessor von C++. In diesem Zusammenhang ist es noch 
erwähnenswert, daß das Verfahren nur bei der if-Abfrage möglich ist, 
denn das Java-System prüft normalerweise darauf, ob Codezeilen erreicht
werden können oder nicht und gibt gegebenenfalls Fehlermeldungen aus. 
Das if-Statement ist jedoch wie oben beschrieben erweitert worden, um 
das gewünschte Verhalten simulieren zu können. Dahingegen wird folgender
Code mit einer Fehlermeldung quittiert:

public class Test {
    final static boolean DEBUG = true;

    public static void main (String[] params) {
        int i = 12;
        while (DEBUG) {
            System.out.println("Der Wert von i ist " + i);
        }
    }
}

Denn es würde sich je nach Zustand von DEBUG eine Endlosschleife
ergeben.


3.1.12. Existiert der const Modifizierer von C++ auch in Java?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C++ kennt das Schlüsselwort const, das es erlaubt, konstante Objekte zu
definieren, deren Wert man nicht ändern kann. Auf ein solches Objekt kann
man nur Methoden anwenden, die ebenfalls als const definiert sind, die 
also die Daten des Objektes nicht ändern können.

Ab Java 1.1 können Argumente mit dem Modifizierer final als konstant
definiert werden. Bei einer Objektreferenz bedeutet dies allerdings nur,
daß die Referenz konstant bleibt, nicht aber das Objekt, auf das die 
Referenz verweist.

Da Java den Modifizierer const nicht kennt, ist es aber trotzdem recht 
einfach möglich, diesen nachzubilden. Alles, was man dazu braucht, ist 
ein Interface, das die konstanten Methoden enthält, die das Objekt nicht
ändern können. Will man nun ein konstantes Objekt zurückgeben oder 
erzeugen, dann gibt man einfach eine Referenz vom Typ des Interfaces 
zurück und schon hat man das Gewünschte erzielt.

Folgendes Beispiel soll das Ganze etwas verdeutlichen:

interface KonstanterTyp {
    public int get();
}

public class NichtKonstanterTyp implements KonstanterTyp {

    int i;

    public void set(int i) {
        this.i = i;
    }

    public int get() {
        return this.i;
    } 
}

Ein konstantes Object wird dann durch

    KonstanterTyp A = new NichtKonstanterTyp();

erzeugt.

Anmerkung: Im Prinzip wird hier durch das Interface eine Art Untermenge 
der Klasse  NichtKonstanterTyp  definiert. Bei C++ läuft dieser Prozeß 
im Prinzip auch so ab, nur wird hier vom Compiler automatisch diese 
Untermenge durch den Modifizierer const erzeugt und der Programmierer 
muß sich hierum nicht kümmern. In Java muß man diesen Prozeß selbst 
durchführen.


3.1.13. Wie kann man Referenzen von Übergabeparametern ändern?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Von Sprachen wie C++ oder Pascal kennt man die Möglichkeit, Referenzen, 
die an die Methode übergeben werden, innerhalb der Methode zu ändern, an
die sie übergeben wurden, wodurch nach dem Aufruf der Methode die 
Referenzen auf andere Objekte verweisen.

In Java gibt es zwei Möglichkeiten, diesen Effekt zu erreichen:

  - Einführen einer weiteren Ebene mit Wrapper-Klassen, die spezielle
    Referenzen zur Verfügung stellen.
  - Verwendung von eindimensionalen, einelementigen Arrays.

Der erste Punkt dürfte klar sein, jedoch steht der Aufwand erst dann in
einem vernünftigen Verhältnis zum Ergebnis, wenn diese Art der 
Parametermodifikation öfter innerhalb des Programms vorkommt, denn 
ansonsten lohnt sich das Design einer speziellen Klasse nicht unbedingt.
Den zweiten Weg verdeutlicht das folgende Programm:

public class Test {
    public void parameterModifikation(Object[] paramter) {
        parameter[0] = "Neue Referenz";
    }
    public static void main (String[] args) {
        Objcet parameter[] = new Object[1];
        parameter[0] = "Zu modifizierender Parameter."
        Test test = new Test();
        System.out.println(parameter[0]);
        test.parameterModifikation(parameter);
        System.out.println(parameter[0]);
    }

}

Das Beispielprogramm liefert folgende Ausgabe:

    Zu modifizierender Parameter
    Neue Referenz


3.1.14. Wie erzeuge ich eine  tiefe  Kopie eines Objektes mit möglichst
        wenig Aufwand?
        Autor: Markus Reitz
        Autor: Ingo R. Homann
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Weist man einer Objektvariablen eine andere zu, so wird nur die Referenz
kopiert und beide Objektvariablen können das Objekt modifizieren und 
diese Modifikation auch sehen. Dies ist das Standardverhalten von Java. 
Durch clone() wird z.B. eine flache Kopie von dem Vector angelegt,
d.h. z.B. das Hinzufügen eines neuen Elements in die Kopie des Vektors
ist im Original-Vector nicht sichtbar. Die enthaltenen Objekte jedoch
werden *nicht* mitkopiert, d.h. Änderungen an den enthaltenen Objekten
sind in beiden Vectoren sichtbar. Wenn wirklich alles - also auch die
enthaltenen Objekte und die rekursiv darin enthaltenen Objekte - kopiert
werden soll, dann braucht man eine sog. tiefe Kopie.

Ein sehr eleganter Weg, eine tiefe Kopie eines Objektes zu erzeugen, 
verwendet den Serialisierungs-Mechanismus. Objekte, die man mit diesem 
Verfahren kopieren möchte, müssen also das Interface Serializable 
implementieren.

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

public class TiefeKopie {
    public static Object kopiere(Object einObjekt) 
            throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);

        oos.write(einObjekt);
        
        ByteArrayInputStream bais = 
                new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        
        return ois.readObject();
    }
}

Zuerst werden zwei Ausgabeströme angelegt: Ein Byte-Strom und ein 
Object-Strom. Der Byte-Strom wird hinter den Object-Strom geschaltet und
das zu kopierende Objekt wird auf dem Object-Strom ausgegeben und durch 
die Verknüpfung der beiden Ströme schließlich in den Byte-Strom 
geschrieben. Dieser Byte-Strom wird dann mit einem zweiten Strom wieder 
eingelesen und mit einem weiteren Object-Strom wird aus den einzelnen 
Bytes wieder ein Objekt rekonstruiert. Die Ausgabe des Object-Stroms ist
dann das kopierte Objekt.

Die Anwendung der Klasse zeigt folgendes Codefragment:

public class Test {
    public static void main(String[] args) {
        int einArray[] = {56, 42, 67, 90, 12, 45};
        int tiefeKopieVonEinArray = (int[]) TiefeKopie.kopiere(einArray);
    }
}

Ein Array ist in Java nichts weiteres als ein Objekt und implementiert 
auch das Serializeable-Interface, weshalb das obige Kopierverfahren 
problemlos greifen kann.

Anmerkung: Bei komplexen Objekten, die viele Referenzen auf andere 
Objekte besitzen schlägt das Verfahren meist fehl. Der 
Serialisierungsmechanismus verwendet Rekursion, um alle referenzierten 
Objekte zu speichern. Wird auf Objekte referenziert, die wieder auf 
Objekte referenzieren usw. kann es geschehen, daß der Stack-Speicher 
für die Rekursion überläuft. Diese elegante Methode der tiefen Kopie 
kann also nur bei  einfachen  Objekten angewendet werden. In Sachen
Performance liegt diese Lösung jedoch um einiges hinter der klassischen
Lösung alle Elemente einzeln zu kopieren. Dessen sollte man sich klar
sein, wenn man diese Lösung einsetzt.


3.1.15. Wie kann ich in Java eine dem Programmierer unbekannt Anzahl
        gleichartiger Objekte erzeugen und ihnen passende Namen zuweisen,
        also label1, label2 usw.?
        Autor: Michael Paap, Christian Kaufhold
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das ist in dieser Form nicht sinnvoll. Die bessere Lösung
besteht in der Verwendung eines Arrays. In Java kann die
Größe eines Arrays bei seiner Erzeugung zur Laufzeit
(einmalig!) festgelegt werden. Ein Zugriff auf die einzelnen
Objekte erfolgt dann über den Arrayindex:


// Deklaration
Label[] myLabels;

...

// Erzeugung und Initalisierung zur Laufzeit
int anzahl = 10;
myLabels = new Label[anzahl];

for (int i = 0; i < myLabels.length; i++) {
    myLabels[i] = new Label("Label Nr. " + i);
}

// Verwendung
myLabel[3].setBackground(Color.red);


3.1.16. Wie kann ich den Typ enum aus C++ in Java umsetzen?
        Autor: Markus Reitz, Uwe Günther, Ulf Jährig
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

C++ bietet einen sogenannten Enumerationstyp. Eine Variable eines 
solchen Typs kann nur definierte Werte annehmen, die mit symbolischen 
Namen bezeichnet werden. Folgende Enumeration könnte zum Beispiel für 
eine Ampel verwendet werden:

    enum Ampel {ROT, GELB, GRUEN};

Java bietet diesen Typ nicht, kann diesen aber recht einfach mit einem   
Interface nachbilden:

interface Ampel {
    public static final int ROT = 1;
    public static final int GELB = 2;
    public static final int GRUEN = 3;
}

Ein C++ Compiler führt automatisch die Zuordnung von Variablennamen zu
eindeutigen Zahlenwerten durch, in Java muß der Programmierer diesen 
Prozeß erledigen. Die Verwendung differiert zwischen Java und C++:

    Ampel eineVariable = ROT; // Das ist C++
    int eineVariable = Ampel.ROT; // Das ist Java

Man erkennt einen großen Nachteil der Java-Version: Da es sich um eine 
int-Variable handelt, ist es prinzipiell möglich, jeden Wert an diese 
Variable zuzuweisen, eben nicht nur Werte aus dem Wertebereich rot, gruen
und gelb. Im Gegensatz dazu läßt ein C++-Compiler nur Zuweisungen von 
Symbolen aus dem Enumerationstyp zu. Insofern ist die Nachbildung in Java
weniger sicher als das C++-Pendant und sollte daher mit Vorsicht 
angewendet werden. Sprich sie ist nicht Typsicher!

Wie schon oben angesprochen, bietet diese direkte Implementierung den 
Nachteil, daß sie nicht typsicher ist. Doch es ist recht einfach möglich,
mit Java eine typsichere Implementierung zu erhalten:

public final class Ampel {

    private String name;
    public final int ord;
    private static int obereGrenze = 0;

    private Ampel(String name) {
        this.name = name;
        this.ord = obereGrenze++;
    }

    public String toString() {
        return this.name;
    }

    public static int groesse() {
        return this.obereGrenze;
    }

    public static final Ampel ROT = new Ampel("Rot");
    public static final Ampel GELB = new Ampel("Gelb");
    public static final Anpel GRUEN = new Ampel("Gruen");
}

Besonders interessant ist hier die Kombination von automatischer 
Zuweisung eines eindeutigen Zahlenwertes mit den Symbolwerten eines 
Strings.

Auf den ersten Blick sieht die Klassendefinition ziemlich kompliziert und
unverständlich aus, das Prinzip ist jedoch nicht schwer zu verstehen:

  - Zuersteinmal ist die Klasse als final deklariert, wodurch verhindert
    wird, daß von dieser Klasse Ableitungen gebildet werden können. Der
    Aufzählungstyp kann also - weder absichtlich noch unabsichtlich - 
    durch Vererbung verändert werden.
    
  - Der Konstruktor der Klasse ist private, dadurch kann er nur von
    der Klasse selbst aufgerufen werden. Damit sind die einzigen 
    Instanzen, die von Ampel erzeugt werden können, die, die den 
    public-Variablen der Klassen zugewiesen sind. 
    
  - Einer Referenz vom Typ Ampel können durch diese Maßnahmen nur die 
    Werte {ROT, GELB, GRUEN} zugewiesen werden, andere Instanzen vom 
    Typ Ampel sind ausgeschlossen, weil sie niemals existieren werden.

  - Die Überlagerung von toString hat den Zweck, einem das Leben beim
    Debuggen einfacher zu machen.

Will man nun diesen Typ von Enumeration benutzen, so sieht das in etwa
wie folgt aus:

public class Test {
    public static void main(String[] args){
        Ampel meineAmpel = Ampel.ROT;

        if (meineAmpel == Ampel.ROT) {
            System.out.println("Ampel ist " + meineAmpel + ". ");
            System.out.println("Anhalten!");
        }
        if (meineAmpel == Ampel.GELB) {
            System.out.println("Ampel ist " + meineAmpel + ". ");
            System.out.println("Motor starten -oder- Anhalten!");
        }
        if (meineAmpel == Ampel.GRUEN) {
            System.out.println("Ampel ist " + meineAmpel + ". ");
            System.out.println("Gib Gas!");
        }
    }
}

Dieser Typ der Enumeration verwendet also Referenzen und nicht, wie 
Version 1, int-Werte, die nicht typsicher sind. Durch die 
Typprüfungsmechanismen von Java wird diese Art von Enumeration 
vollkommen typsicher und steht dem enum Konstrukt von C++ nun in nichts
mehr nach.

Wer mehr über dieses Pattern erfahren möchte sei dem sei folgender Link
empfohlen:

<URL:http://www.javaworld.com/javaworld/jw-07-1997/jw-07-enumerated.html>


3.1.17. Kann man Mehrfachvererbung mit Java simulieren?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java kennt im Gegensatz zu C++ nicht das Feature der Mehrfachvererbung, 
eine Klasse kann nur genau einen Vorfahren haben, im Gegensatz zu 
beliebig vielen bei Mehrfachvererbung.

Häufig liest man, daß man die Mehrfachvererbung mit Hilfe von Interfaces
nachbilden kann, indem man die Methodenschnittstelle der einzelnen 
Klassen als Interfaces definiert und diese Interfaces alle gleichzeitig 
von der fraglichen Klasse implementieren läßt, denn dies ist in Java 
möglich.

Mit Mehrfachvererbung hat dies aber nichts zu tun, wenn man den 
eigentlichen Sinn und Zweck von Vererbung betrachtet. Vererbung ist 
eines der möglichen Prinzipien, um die Codewiederverwertung zu 
garantieren. Code, der in mehreren Klassen benötigt wird, ist nur in der
Basisklasse aufgeführt und durch die Vererbung können die  Erben  auch 
diesen Code benutzen. Der Code steht also nur an einer Stelle. Bei der 
oben beschriebenen  Nachbildung  wird in keiner Weise Code gespart, denn
die Methoden der Interfaces müssen ja von der Klasse noch implementiert 
werden.

In diesem Sinne kann man Mehrfachvererbung nicht in Java nachbilden.


3.1.18. Wie realisiere ich eine variable Parameterliste?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Es gibt Anwendungsfälle, in denen es äußerst nützlich wäre, einer 
Methode eine variable Anzahl an Parametern übergeben zu können. Ein
Anwendungsfall wäre eine Klasse beliebig-dimensionaler Vektoren. Ein 
Konstruktor dieser Klasse müßte die Initialisierung eines Vektors mit 
bestimmten Werten erlauben und da beliebig-dimensionale Vektoren von 
dieser Klasse verarbeitet werden, müßte der Konstruktor mit einer 
variablen Parameteranzahl arbeiten können. Mit einem Trick kann man eine
variable Parameterliste realisieren: Man übergibt der Methode ein Array 
von Referenzen auf die Klasse Object. Da in Java alle Objekte von der 
Klasse Object abstammen - sie ist quasi die Klasse aller Klassen - kann 
das Array Referenzen auf beliebige Objekte aufnehmen. Innerhalb der 
Methode kann dann mit dem length-Feld des Arrays die Anzahl der 
übergebenen Parameter ermittelt werden. Mit dem instanceof-Operator von 
Java kann dann der Typ des Objekts ermittelt werden, auf den die 
Referenzen verweisen und an Hand dieser Informationen kann man dann 
festlegen, was getan werden soll. Ein Programmfragment verdeutlicht das 
bisher Gesagte:

public class Test {
    void methodeMitVariablerParameterListe(Object[] parameterList) {
        //Länge: parameterList.length ===> Anzahl der Parameter
        //Typ:   if (parameterList[i] instanceof <Type>)  
    }
}

Ein Nachteil ist offensichtlich: Es kann nur genau eine Methode mit 
variabler Parameterliste geben bzw. innerhalb dieser einen Methode müssen
alle Variationen berücksichtigt und implementiert werden, was nicht 
unbedingt zur Übersichtlichkeit des Programms beiträgt.

Ein Aufruf der Methode gestaltet sich nun wie folgt:

Test obj = new Test();
obj.methodeMitVariablerParameterListe(new Object[] {
        paramObject1, paramObject2, ..., paramObjectn
    });

Will man elementare Datentypen wie double oder int an die Methode
übergeben, so muß man die zugehörigen Wrapper-Klassen verwenden, die 
diese elementaren Datentypen in Klassen  einpacken.    


3.1.19. Wie realisiere ich eine Methodenauswahl nach den dynamischen
        Parametertypen?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java wählt Methoden nach dem statischen Typ der Übergabeobjekte aus. Man
kann jedoch eine dynamische Auswahl simulieren, indem man das oben 
angesprochene Prinzip der variablen Parameter hierauf überträgt. Man 
prüft die übergebenen Referenzen mit dem instanceof-Operator, der den 
dynamischen Typ des Parameters liefert. Anhand dieser Informationen kann
man dann ein  dynamisches  Verhalten der Methodenaufrufe realisieren. 
Auch hier gilt, wie auch schon bei der variablen Parameterliste, daß eine
einzige Methode alle Aufrufmöglichkeiten abdecken muß.


3.1.20. Sind Methoden in Java immer virtuell?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Java sind alle Methoden virtuell, eine Unterscheidung zwischen 
virtuellen und nicht-virtuellen Methoden wie zum Beispiel in C++, gibt es
in Java nicht. Ist es für die Funktionsweise eines Objektes wichtig, daß
die vorhandenen Methoden nicht überschrieben werden können - etwa um zu 
verhindern, daß sich die Funktionalität des Objekts dadurch grundlegend 
ändern läßt - so muß man entsprechende Methoden mit dem Modifizierer 
final deklarieren, der ein Überschreiben verhindert.


3.1.21. Ich stosse ab und zu auf den Begriff "Wrapper-Klassen".
        Könnte mir jemand erklären was das ist? 
        Autor: Stephan Menzel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Eine sehr gute Frage, auf die ich mal mit einem Zitat aus Go to Java 2
antworten moechte, denn sie wird zu selten gestellt:

Zitat (Goto Java 2):

Zu jedem primitiven Datentyp in Java gibt es eine korrespondierende
Wrapper-Klasse. Diese kapselt die primitive Variable in einer
objektorientierten Hülle und stellt eine Reihe von Methoden zum Zugriff
auf die Variable zur Verfügung. Zwar wird man bei der Programmierung
meist die primitiven Typen verwenden, doch gibt es einige Situationen, 
in denen die Anwendung einer Wrapper-Klasse sinnvoll sein kann.

Diese Klassen, wie zum Beispiel "Integer" koennen einem das Leben 
angenehmer gestalten, wenn man Dinge tun muss, die man mit einfachen 
ints tun will, aber mangels vorhandener Methoden nicht kann, weil diese
Primitiven eben keine richtigen Objekte sind.

Zum Beispiel kann Integer (im Gegensatz zu int) Strings nach Zahlen
parsen, oder Integers als Binaercode ausgeben oder als Hex oder in 
andere Zahlentypen umwandeln und vieles mehr. Vielleicht ist es fuer 
Dich noch interessant zu erfahren, dass diese Wrapper Klassen in der 
Praxis oftmals nicht instantiiert, sondern ihre Methoden statisch 
aufgerufen werden.

Um zum Beispiel aus dem String "42" das betreffende int zu machen, 
rufst Du:

String zweiundvierzig = new String ("42") ;
int answer = Integer.parseInt (zweiundvierzig) ;

Das brauchst Du zum Beispiel zum Auswerten von GUI-Zahlenfeldern.
Ich hoffe, ich konnte ein wenig Licht ins Dunkel bringen. Das 
Verstaendnis von Wrapperklassen und deren Sinn halte ich naemlich fuer
essentiell, wenn man mit OOP beginnt.


3.1.22. Warum ist private nicht privat?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public class Person {

    private int kontostand;

    public Person(int kontostand) {
        this.kontostand = kontostand;
    }

    public void addGehalt(int gehalt) {
        this.kontostand += gehalt;
    }

    public void klauen(Person opfer) {
        this.kontostand += opfer.kontostand;
        opfer.kontostand = 0;
    }

    public void zeigeKontostand() {
        System.out.println("Kontostand: " + this.kontostand);
    }
}


public class Test {
    public static void main(String[] args) {
        //Der Dieb eröffnet ein Konto
        Person dieb = new Person(10);

        //Das Opfer eröffnet ein Konto
        Person opfer = new Person(50000);

        //Das Opfer bekommt Gehalt
        opfer.addGehalt(10000);
        
        //Der Dieb geht an die Arbeit
        dieb.klauen(opfer);

        //Das opfer ist nun pleite!!!
        opfer.zeigeKontostand();
        
        //Und der Dieb un 60000 Euro reicher.
        dieb.zeigeKontostand();
    }
}


Wenn man obiges Programm testet, so wird man feststellen, daß es möglich
ist, die private-Datenfelder eines Objektes zu manipulieren; diese Daten
sind also nicht privat im sonst üblichen Sinne. Allerdings ist die 
Privatsphäre nur für Objekte der gleichen Klasse aufgehoben, Objekte 
anderer Klassen haben keinen Zugriff auf die private-Daten von Objekten 
anderer Klassen. Damit ist obige Möglichkeit nicht weiter tragisch, denn
der Entwickler der Klasse kann eine wie oben gezeigte Möglichkeit 
wirksam unterbinden. Wenn er dies nicht tut, so ist die Schuld bei ihm 
zu suchen, denn nur der Entwickler allein ist für das Verhalten der 
Klassen zuständig und nur der Entwickler muß solche Möglichkeiten durch 
das Design ausschließen. Die private-Deklaration ist damit als 
Deklaration der Privatsphäre gegenüber Objekten anderer Klassen zu 
sehen, zwischen Objekten der gleichen Klasse herrscht ein 
freundschaftliches Verhältnis, sie dürfen sich gegenseitig in die Daten 
schauen.





3.2. [STRING] - Fragen die unmittelbar mit Strings zu tun haben.
----------------------------------------------------------------

3.2.1. Wie vergleiche ich zwei Strings in Java?
       Autor: Markus Reitz, Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Problem:

Man versucht zwei Strings in der Form

if(stringEins == stringZwei) {
    System.out.println("stringEins und stringZwei sind gleich.");
}

zu vergleichen und erhält alles andere als ein richtiges Ergebnis. 

Der Grund ist der, daß mit dem "=="-Operator nur die beiden Referenzen
miteinander verglichen werden, nicht jedoch die Objekte. Man erhält 
deshalb womöglich auch bei zwei gleichen Strings das Ergebnis, daß sie 
verschieden sind. Für den inhaltlichen Vergleich, nicht nur von Strings,
sondern allgemein von Objekten, wird in Java die Methode 
equals(Object obj) verwendet, die nicht immer nur Referenzen, sondern
je nach Klasse auch die Inhalte (sprich ihre Daten) vergleicht. Obige 
Abfrage müßte also

if(stringEins.equals(stringZwei)) {
    System.out.println("stringEins und stringZwei sind gleich.");
}

lauten, damit das gemacht wird, was eigentlich gewünscht ist. 


Im Zusammenhang mit Strings ist noch eine Besonderheit zu erwähnen:

if ("Java".equals(stringZwei)) {
    System.out.println("stringZwei ist gleich zu Java.");
}

ist zulässig, der Compiler erzeugt aus
der Zeichenkette automatisch ein String-Objekt; man muß also nicht 
zuerst ein Objekt anlegen und den String Java dort speichern.


3.2.2. Wie wandle ich einen String in einen Integer?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Klassen können Methoden besitzen, die die Konvertierung eines Objekts
dieser Klasse in ein Objekt einer anderen Klasse übernehmen. Zu dem 
elementaren Java-Datentyp int gibt es eine sogenannte Wrapper-Klasse 
Integer, die den elementaren Datentyp in einer Klasse kapselt .Diese 
Klasse stellt eine Methode (in diesem Fall eine Klassenmethode) zur 
Verfügung, die das Gewünschte leistet:

public class Test {
    public static void main (String[] params) {
        String stringMitZahl = "50";
        int zahl = 0;
        try {
            zahl = Integer.parseInt(stringMitZahl);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        zahl = zahl + 10;
        System.out.println("Die Variable zahl = " + zahl);
    }
}


3.2.3. Wie wandle ich einen Integer in einen String um?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dieses Problem ist genau das Gegenteil des vorherigen. Wie die Klasse
Integer, so besitzt auch die Klasse String eine Methode, die das 
Problem löst, allerdings heißt die Methode nicht parseString, was man 
analog schließen könnte, sondern valueOf.

public class Test {
    public static void main (String[] params) {
        int zahl = 50;
        String stringMitZahl = String.valueOf(zahl);
        System.out.println("Die Variable stringMitZahl = " + 
                stringMitZahl);
    }
}


3.2.4. Wie wandle ich einen Integer in einen HexString um?
       Autor: Uwe Günther
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das Problem ist ähnlich wie das Konvertieren von einem Integer in einen
String. Wie die Klasse String die Klassenmethode valueOf besitzt, um
einen String zu erzeugen, so besitzt die Klasse Integer die 
Klassenmethode toHexString(int i).

public class Test {
    public static void main (String[] params) {
        int zahl = 50;
        String stringAlsHex = Integer.toHexString(zahl);
        System.out.println("Die Variable stringAlsHex = " + 
                           stringAlsHex);
    }
}

Der Nachteil der Integer.toHexString(int i) Methode ist, dass sie alle
führenden Nullen einer Hex-Repräsentation abschneidet.


3.2.5. Wie kann ich eine Zahl formatieren und wie lege ich die Anzahl der
       Nachkommastellen fest?
       Autor: Karsten Schulz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das kann die Klasse java.text.NumberFormat und deren Abkömmlinge
erledigen.

Beispiel:

import java.text.DecimalFormat;

public class Zahl {
    public static void main(String[] args) {
        double betrag = 1000d/3d; // -> 333.333333...
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println(df.format(betrag));
        df = new DecimalFormat("#.## DM");
        System.out.println(df.format(betrag));
        df = new DecimalFormat("0000.0000");
        System.out.println(df.format(betrag));
    }
}

Die Ausgabe des Programms sind formatierte Dezimalzahlen:
333,33
333,33 DM
0333,3333

In der API-Dokumentation der Klassen java.text.Decimalformat und 
java.text.NumberFormat werden alle weiteren Formatierungsoptionen
erläutert. Falls die Umwandlungen von double nach String 
zeitkritisch durchgeführt werden müssen, lohnt sich ein Blick auf
<URL:http://www.onjava.com/pub/a/onjava/2000/12/15/formatting_doubles.html>
Dort erklärt Jack Shirazi (Autor des Buches "Java Perfomance Tuning")
andere Konvertierungsmethoden.


3.2.6. Wie kann ich ein Datum formatieren?
       Autor: Karsten Schulz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das machen andere für Dich,...

Benutze einfach die Klassen DateFormat aus dem package java.text.
Folgendes Beispiel zeigt Dir die Anwendung der SimpleDateFormat-Klasse:

import java.util.Date;
import java.text.SimpleDateFormat;

public class Datum {
    public static void main(String[] args) {
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sd.format(new Date()));
        sd.applyPattern("dd.MM.yyyy");
        System.out.println(sd.format(new Date()));
    }
}

Die Ausgabe des Programms sind formatierte Datümer:

    2000-12-24
    24.12.2000

In der API-Dokumentation zur Klasse java.text.SimpleDateFormat sind die
Kürzel der verschiedenen Datumskomponenten für Tag, Monat, usw. 
aufgeführt.


3.2.7. Wie kann ich in einem String oder StringBuffer mehrere Zeichen
       suchen und ersetzen?
       Autor: Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mit

    String String#replace(char,char)

kann ich nur einzelne Zeichen suchen und mit

    StringBuffer replace(int,int,String)

nur ersetzen aber nicht suchen.

Lösung:

Eine gute Hausaufgabe. Was man hier braucht, ist eine Kombination von

    int String#indexOf(String,int),
    String String#substring(int,int)

mit einem neu aufzubauenden StringBuffer.

bzw.

    int StringBuffer#indexOf(String,int)
    StringBuffer#replace(int,int,String)


Die folgende Lösung ist eine unter vielen und ersetzt alle Vorkommen von
"search" in "source" mit "replace":

public static String replaceAll(String source, String search, 
                                String replace) {
    if(search.equals(replace)) {
        return source; //kann ja sein, dass wir nichts tun müssen
    }

    StringBuffer result = new StringBuffer();
    int len = search.length();
    if(len == 0) {
        return source; //verhindert Endlosschleife bei search.equals("");
    }

    int pos = 0; //position
    int nPos;    //next position
    do {
        nPos = source.indexOf(search, pos);
        if(nPos != -1) { //gefunden
            result.append(source.substring(pos, nPos));
            result.append(replace);
            pos = nPos+len;
        } else { //nicht gefunden
            result.append(source.substring(pos)); //letzter abschnitt
        }
    } while(nPos!= -1);

    return result.toString();
}

Da sowas praktisch überall gebraucht wird, gibt es unzählige
Bibliothek(chen) im Netz, die so etwas anbieten, z.B.

<URL:http://ostermiller.org/utils/StringHelper.java.html>

BTW: Der Link muss as den 3 Zeilen zusammen gestzt werden!

[...vielleicht noch mehr und geeignetere Adressen...]



3.2.8. Gibt es reguläre Ausdrücke in Java (regular expressions)? 
       Autor: Karsten Schulz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ja, natürlich.

Bis zum J2SDK 1.4 muss man, um reguläre Ausdrücke in Java zu benutzen,
auf externe packages zurückgreifen. Eines der ausgereiftesten ist das 
Regexp-Paket aus dem Jakarta-Projekt:

    http://jakarta.apache.org/regexp/index.html

Ab dem J2SDK 1.4 wird es jedoch ein package java.util.regex geben, das
somit die Möglichkeit zur Benutzung der regulären Ausdrücke direkt in die
Klassenhierarchie einbaut.

Nachfolgend ein Beispiel für die Nutzung dieses packages (Achtung: 
funktioniert nur ab J2SDK 1.4 aufwärts!).

Das Beispielprogramm zeigt, wie in der Stringvariablen 'input'
nach einem Muster (Pattern) gesucht wird, das auf einer Ziffer,
mindestens einem Buchstaben und einer weiteren Ziffer besteht:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PatternTest {

    public static void main(String[] args) {
        String input = "Test für Regex Ausdrücke 1xxx2 n444n.";
        Pattern p = Pattern.compile("\\d\\D+\\d");
        // Muster: Ziffer, mind. ein Buchstabe, Ziffer
        Matcher m = p.matcher(input);
        if (m.find()) {
            System.out.println("Muster an Pos. " + m.start());
                System.out.println("Muster ist: " + m.group());
        } else {
            System.out.println("Muster nicht gefunden");
        }
    }
}

Die Ausgabe dieses Programms ist:

    Muster an Pos. 25
    Muster ist: 1xxx2

Weitere Infos in der API-Dokumentation zu java.util.regex.




3.3. [IO] - Frage bezüglich Eingabe/Ausgabe, Streams, etc. in Java.
-------------------------------------------------------------------

3.3.1. Verlangsamt Serialisierung mein Programm?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java bietet mit dem Mechanismus der Serialisierung auf einfache Weise 
die Möglichkeit, den aktuellen Zustand des Objekts auf einem 
Datenträger, das Netz oder sonst wohin über einen Stream zu sichern. Der
verwendete Mechanismus ist relativ kompliziert, damit auch alle 
auftretenden Möglichkeiten korrekt behandelt werden können. Sind die 
Daten der Objekte sehr groß, so empfiehlt es sich, eigene Prozeduren 
zur Speicherung zu entwickeln, die dann nicht mehr allgemeingültig, aber
auf die aktuelle Verwendung angepaßt und damit schneller sind.


3.3.2. Wie kann ich rekursiv einen Verzeichnisbaum abarbeiten?
       Autor: Marco Schmidt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In java.io.File befinden sich die dazu benötigte Funktionalität. Mit 
list() läßt man sich ein Array mit allen Dateinamen geben, mit 
isDirectory() läßt sich prüfen, ob es sich bei dem File-Objekt um ein
Verzeichnis handelt. Indem man nun rekursiv in Unterverzeichnisse 
absteigt, kann man so einen kompletten Verzeichnisbaum abarbeiten.

Hier ein Beispielprogramm (scantree.java):
  
import java.io.File;

public class scantree {
    public static void main(String[] args) {
        // Programm muss einen Verzeichnisnamen als Parameter haben
        File dir = new File(args[0]);
        scan(dir);
    }

    public static void scan(File dir) {
        // Liste aller Dateien und Unterverzeichnisse holen
        String[] entries = dir.list();
        if (entries == null || entries.length < 1) {
            return;
        }
        for (int i = 0; i < entries.length; i++) {
            File entry = new File(dir, entries[i]);
            if (entry.isDirectory()) {
                scan(entry); // rekursiv ins Unterverzeichnis verzweigen
            } else {
                // entry ist eine Datei
                System.out.println(entry);
            }
        }
    }
}


3.3.3. Wie kann ich aus Dateien zeilenweise lesen?
       Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Generell nutzt man für die Datei-Operationen einen Buffered Reader oder
eine Klasse, die von dieser abstammt. Diese Klasse besitzt dann die 
Methode readLine(), die eine Zeile aus der Datei ausliest und diese Zeile
als einen String zurückgibt.

Zu beachten ist, daß bei Erreichen des Dateiendes kein leerer String,
sondern eine Nullreferenz zurückgegeben wird. Ein Programm, daß aus einer
Datei zeilenweise liest, sieht in Java wie folgt aus:

import java.io.*;

public class ZeilenWeiseLesen {
    public static void main(String[] args) {
        try {
            String zeile;

            //Wir lesen aus "eingabe.txt".
            File eingabeDatei = new File("eingabe.txt");
            FileReader eingabeStrom = new FileReader(eingabeDatei);
            BufferedReader eingabe = new BufferedReader(eingabeStrom);

            while ((zeile = eingabe.readLine()) != null) {
                System.out.println(zeile);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


3.3.4. Wie kann ich Exponentialzahlen (z.B. 1.09E+008) aus einer Datei 
       lesen?
       Autor: Wolfram Rühaak
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mit Java führt folgendes Verfahren zum Ziel:
Lies die Daten als Strings ein und wandel sie mittels
Double.valueOf(my_string).doubleValue()
in einen double Wert um.

Das StreamTokenizer keine Exponentialzahlen kennt hat von Sun Bug Status
bekommen (obgleich der StreamTokenizer so arbeitet wie angegeben):
* BugId: #4079180
  Synopsis:  java.io.StreamTokenizer: Add ability to read full Java
  floating-point syntax
  Der Sun Workaround soll wohl ein:
      public void parseExponentialNumbers(boolean flag)
   sein.

Beispiel:
import java.io.*;
import java.util.Vector;
/**
 * @author Wolfram Rühaak
 * Beispielcode, der zeigt wie man Zahlen aus einer Datei liest.
 * Die Datei darf in diesem Fall nur Zahlen enthalten, getrennt durch
 * Tabulator oder Space.
 * Die Anzahl von Spalten/Zeilen ist nicht vorgegeben.
 * Um *.cvs Kompatibilät zu erhalten kann man als whitespaceChars
 * noch ',' und ';' hinzufügen.
 */
public class ReadExponential {

    int ni; // Anzahl Zeilen
    int nj; // Anzahl Spalten

     private ReadExponential(String Filename) {
         int i=0; 
         int j=0;
         Vector v2 = new Vector();

         try {
             FileInputStream fis = new FileInputStream(Filename);
             BufferedReader r = 
                     new BufferedReader(new InputStreamReader(fis));
             StreamTokenizer st  = new StreamTokenizer(r);
             /*
              * Nachfolgendes Code-Fragment von:
              * Mark Gritter ([EMAIL PROTECTED])
              * Betrifft:Re: This is easy in C++ (asking for help)
              * Newsgroups:comp.lang.java.programmer
              * Datum:1997/11/07
              */
             st.resetSyntax();
             st.whitespaceChars(' ', ' ');
             st.whitespaceChars('\n', '\n');
             st.wordChars('0','9');
             st.wordChars('e','e');
             st.wordChars('E','E');
             st.wordChars('.','.');
             st.wordChars('+','+');
             st.wordChars('-','-');
             /* Ende Code-Fragment */
            st.eolIsSignificant(true);

            try {
                while(st.nextToken() != st.TT_EOF) {
                    String s1 = st.sval;
                    if(s1!=null) {
                        // Wert in Vector schreiben
                        v2.addElement(s1);     
                        // Anzahl von Zeilen
                        i=st.lineno();         
                    }
                }
            } catch(IOException ioe) {}
        } catch (FileNotFoundException fnfe) {}
        ni = i - 1;
        nj = ((v2.size())/(ni+1))-1;   // Anzahl von Spalten berechnen

        double[][] dAllValues = new double [ni+1][nj+1];
        int k=0;
        for(i = 0;i <= ni; i++) {
            for(j = 0;j <= nj; j++) {
                Object f = v2.elementAt(k); // Vector in
                String s = f.toString();    // Array umspeichern
                /*
                 * Double.valueOf(String s) kann jeden numerischen Wert 
                 * von String nach double umwandeln 
                 */    
                dAllValues[i][j] = Double.valueOf(s).doubleValue();
                k++;
            }
        }
    }
}




3.3.5. Wie kann ich mit Java Dateien kopieren?
       Autor: Martin Erren, Uwe Günther, Ulf Jährig, Christian Kaufhold
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Bestimmt die performanteste Lösung wäre, mit

 System.exec(...)

die Aufgabe dem Betriebssystem zu übergeben.

Der Nachteil ist hier, dass so schwer ein plattformunabhängiger
Code erreichbar ist und die Fehlerbehandlung schwierig wird.

Deshalb einfach eine Datei lesen und in eine andere, neue
Datei schreiben, z.B. so:

import java.io.*;

public static void copyFile(File src, File dest, int bufSize, 
        boolean force) throws IOException {
    if(dest.exists()) {
        if(force) {
            dest.delete();
        } else {
            throw new IOException(
                    "Cannot overwrite existing file: " + destName);
        }
    }
    byte[] buffer = new byte[bufSize];
    int read = 0;
    InputStream in = null;
    OutputStream out = null;
    try {
        in = new FileInputStream(src);
        out = new FileOutputStream(dest);
        while(true) {
            read = in.read(buffer);
            if (read == -1) {
                //-1 bedeutet EOF
                break;
            }
            out.write(buffer, 0, read);
        }
    } finally {
        // Sicherstellen, dass die Streams auch
        // bei einem throw geschlossen werden.
        // Falls in null ist, ist out auch null!
        if (in != null) {
            //Falls tatsächlich in.close() und out.close() 
            //Exceptions werfen, die jenige von 'out' geworfen wird.
            try {
                in.close();
            }
            finally {
                if (out != null) {
                    out.close();
                }
            }
        }
    }
}


Das schwierigste ist hier wohl die Fehlerbehandlung, die je nach 
Anforderung unterschiedlich sein kann.

Anmerkung: Ein paar exotische VMs optimieren read(byte[]) bzw. 
write(byte[]) nicht, so dass hier ein BufferedInputStream oder 
BufferedOutputStream evtl. angebracht ist.


3.3.6. Wie kann man auf programmnahe Resourcen (Button-images, 
       local String properties,...) zugreifen, ohne absolut oder relativ
       zu user.dir adressieren zu müssen (ich will das ganze auch in ein
       jar packen können)?
       Autor: Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    URL Class#getResource(String)

und

    InputStream Class#getResourceAsStream(String)

sind Deine Freunde. Laut API-doc ist "/img.jpg" relativ zur codeBase, 
also dem aktuellen Eintrag im CLASSPATH, wo Deine Klasse geladen wurde, 
und "img.jpg" relativ zur Klasse, also im selben Verzeichnis, wo auch 
die Klasse liegt.

Ob Applikation oder Applet, *.jar oder file-system spielt hier keine 
Rolle.

mit

    System.out.println(MyClass.class.getResource("/").toString());

kannst Du jederzeit feststellen, welche codebase die jeweilige Klasse 
hat.

Weiterhin sind

    InputStream ClassLoader.getSystemResourceAsStream(name);

und

    URL ClassLoader.getSystemResource(name)

für eigene Resourcen nicht zu empfehlen.

[Hier fehlt die Begründung]




3.4. [NET] - Frage bezüglich Netzwerk.
--------------------------------------

3.4.1. Wie kann ich einen Ping in Java realisieren?
       Autor: Stephan Menzel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Eigentlich gar nicht. Ein Ping (ICMP) ist eine hardwarenahe 
Angelegenheit, die im Gegensatz zu dem hardwarefernen abstrahierenden
Konzept von Java steht. Die Antworten einer Netzwerkkarte sind da nicht 
so sehr relevant, wie ein im Netzwerk vorhandener Dienst. So kann zum
Beispiel ein Rechner auf Pings nicht antworten und trotzdem einen Dienst
anbieten. Oder die Pings verenden an einer Firewall oder aber der Rechner
auf dem das Programm laeuft, ist gar nicht in der Lage, zu pingen.
Das bedeutet, es ist sicherer und besser, einfach eine Testweise
Socketverbindung zu der betreffenden Zieladresse aufzubauen und eine 
evtl. auftretende Exception als Zeichen fuer dessen Abwesenheit im Netz 
zu deuten.

Folgendes Beispiel soll dies zeigen:

import java.io.*;
import java.net.*;
..

 static Socket nntpsock; // Der Socket fuer die Newsverbindung
 static BufferedReader in;
 static OutputStreamWriter out;

...

try {
    nntpsock = new Socket("news.cis.dfn.de", 119); // Verbinden
    nntpsock.setSoTimeout(300); // Timeout auf 300ms
    in = new BufferedReader(
            new InputStreamReader(nntpsock.getInputStream()));
    out = new OutputStreamWriter(nntpsock.getOutputStream());
} catch (UnknownHostException e) {
    System.err.println("Unknown Host.:" + e.toString());
} catch (IOException e) {
    System.err.println("Rechner nicht erreichbar.  :" + e.toString());
}

...






3.5. [AWT] - Frage bezüglich AWT.
---------------------------------

3.5.1 Wenn ich einen Listener bei mehreren Buttons anmelde, wie kann ich
      dann unterscheiden, welcher gedrückt wurde?
      Autor: Michael Paap, Christian Kaufhold, Georg Lippitsch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Wenn Du so vorgehst wird, egal welcher Button geclickt wird, die Methode
actionPerformed(ActionEvent ev) des Listeners aufgerufen.

Mit ev.getSource() bekommst Du nun eine Referenz auf die Ereignisquelle 
(als Object). Dann kannst Du schauen, welcher Button geclickt wurde, 
z.B. indem Du diese Ereignisquelle mit den vorhandenen Buttons 
vergleichst oder indem Du auf Button castest und ihre Beschriftung 
ausliest.

Beispiel:

Angenommen, Du hast einen ActionListener bei jedem Button
eines Arrays von 4 Buttons registriert. Dann könnte die
Methode actionPerformed im Listener wie folgt aussehen:

public void actionPerformed(ActionEvent ev) {
    int pressed = -1;
    for (int i=0; i<myButtons.length; i++) {
        if (myButtons[i] == ev.getSource()) {
            pressed = i;
            break;
        }
    }

    // hier abhängig von pressed verschiedene Aktionen
    // ausführen
}

oder so:

public void actionPerformed(ActionEvent ev) {
    Button pressed = (Button) ev.getSource();
    System.out.println("Pressed: " + pressed.getLabel());
}


Eine weitere Möglichkeit bietet die Methode 

    Button#setActionCommand(String command)

Hiermit kann ein dem Knopf ein beliebiger String zugewiesen. Dieser kann
mit 

    ActionEvent#getActionCommand() 

wieder abgefragt werden. Dabei wird immer der String zurückgegeben, der 
dem Event auslösenden Knopf zugewiesen wurde.
 
Ein Beispiel:
 
Button knopf1 = new Button("Max");
knopf1.setActionKommand("schlimmer bub 1");
Button knopf2 = new Button("Moritz");
knopf2.setActionKommand("schlimmer bub 2");
 
public void actionPerformed(ActionEvent ev) {
    String c = ev.getActionCommand();
    if (c.equals("schlimmer bub 2"))
        System.out.println("Moritz wurde aktiviert");
}




3.5.2. Kann ich ein Fenster (Frame/JFrame) maximieren?
       Autor: Karsten Schulz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Antwort: Jein.

Bis zum J2SDK 1.3 (einschließlich) gibt es keine Möglichkeit, ein
Fenster zu maximieren. Es gibt nur verschiedene Workarounds, um ein
Fenster möglichst flächendeckend auf dem Desktop darzustellen (s.u.)

Ab dem J2SDK1.4 gibt es die Methode setExtendedState(int state) aus
der Klasse java.awt.Frame, mit der das Fenster *vielleicht* 
maximiert wird. Ob das möglich ist, kann mittels
isFrameStateSupported(int state) aus dem Toolkit ermittelt werden,
denn nicht jede Plattform unterstützt solche maximierten Fenster.

Für Anwendungen, die mittels einer J2SDK-Version bis 1.3 erstellt werden
sollen, gibt es nur Workarounds, da es eine "Maximieren"-Funktion
nicht gibt. Für den Windows-Benutzer mag das merkwürdig sein, für
den Unix-Benutzer ist der Gedanke merkwürdig, dass die tatsächliche
Bildschirmgrösse etwas mit der Desktopgröße zu tun haben sollte.

Lange Rede, kurzer Code:
um ein Fenster möglichst groß zu machen, nehme man
  setSize(getToolkit().getScreenSize());

Hierdurch wird das darzustellende Fenster vielleicht auf die Größe
der aktuellen Bildschirmauflösung gesetzt. Ohne Berücksichtigung
evtl.  darzustellender Menü- und/oder Taskleisten. 

Falls auf der Laufzeitplattform ein öffnendes Programmfenster von
einem Fenstermanager platziert wird, hat die setSize(Dimension)-Methode
möglicherweise keine Auswirkung auf das Fenster. Der Programmierer sollte
sich also nicht darauf verlassen, dass sein Fenster so dargestellt wird,
wie er es programmiert hat!

Eine weitere Möglichkeit, ein Fenster evtl. zu maximieren besteht
darin, die Klasse java.awt.Robot (seit J2SDK 1.3) zu benutzen, um die
Maximieren-Schaltfläche programmgesteuert anklicken zu lassen.
Hinweise zur Benutzung dieser Klasse finden sich im JDC Tech Tip
vom 11. Juli 2000 
<URL:http://developer.java.sun.com/developer/TechTips/2000/tt0711.html)

Wegen dieser ganzen Unwägbarkeiten ist es oft eine Alternative, statt
das Fenster zu maximieren, es einfach Wiederherzustellen und die Größe
und Position des Fensters von einem vorherigen Programmlauf zu benutzen.
Hierbei sollte jedoch darauf geachtet werden, dass die Geometrie eines
maximierten Fensters *nicht* durch ein normales Fenster nachgebildet
wird, weil der Anwender sonst dadurch verwirrt wird, dass das Fenster
maximiert aussieht, es aber in Wirklichkeit nicht ist!


3.5.3. Wie tausche ich die Kaffeetasse im blauen Balken aus?
       Autor: Karsten Schulz, Roger Schuster, Christian Wederhake
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit java.awt.Frame#setIconImage(java.awt.Image).

Beispiel:

    ImageIcon icon = new ImageIcon("meinBildchen.gif");
    setIconImage(icon.getImage());


3.6. [SWING] - Frage bezüglich Swing.
-------------------------------------

3.6.1. Wie mache ich globale Font-Änderung für meine Komponenten?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* UIManager.put("component.font", new FontUIResource(...));


3.6.2. Wie kann ich bei der Eingabe in ein JTextField die Anzahl
       der eingebbaren Zeichen beschränken?
       Autor: Alexander Elsholz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Wenn ein JTextField benutzt wird sollte man ein
benutzerdefiniertes Document implementieren. Für
AWT-Textfelder funktioniert es mit einigen Anpassungen
auch über das Interface KeyListener.


import javax.swing.text.PlainDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.AttributeSet;

/**
 * Diese Klasse ist ein Dokument für Textfelder, welches die Eingabe auf
 * x Zeichen begrenzt.
 *
 * Die Zuweisung geschieht über 
 * JTextfield.setDocument(new Validation(int anzahl));
 */
public class Validation extends PlainDocument{
    private int limit;

     /**
      * Konstruktor für das Validationdokument
      * @param int limit: maximale Anzahl der einzugebenen Zeichen
      */
     public Validation(int newLimit){
         super();
         if (limit < 0){
             limit = 0;
         } else {
             limit = newLimit;
         }
     }

    /**
     * Funktion überschreibt die Methode insertString von PlainDocument
     * @param int offset: Position
     * @param String str: der String
     * @param AttributeSet attr: Attributset
     */
    public void insertString (int offset, String str, AttributeSet attr)
            throws BadLocationException {
        if (str == null) return;

        if ((getLength() + str.length()) <= limit){
            super.insertString(offset, str, attr);
        }
     }
}

Die hier aufgezeigte Lösung zur Begrenzung von Textfeldern kann auch
verwendet werden, wenn unerwünschte Zeichen in einem Textfeld nicht
eingegeben werden dürfen.


3.6.3. Wie setze ich den Cursor an den Anfang der JTextArea?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* textarea.setCaretPosition(0);


3.6.4. Wie scrolle ich an das Ende der JTextArea?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hierzu existieren mehrere Möglichkeiten:

* textarea.setCaretPosition(textarea.getDocument().getLength());

* try{

  textarea.scrollRectToVisible(textarea.modelToView(
                           textarea.getDocument().getLength()));

  } catch (BadLocationException be) {
           be.toString();
}

* (Geht auch, weniger schön): mit getText().length();


Scrolling wrappen in SwingUtilities.invokeLater(), bspw:

SwingUtilities.invokeLater(new Runnable() {

   public void run() {

   // scrolling code

  }
};


3.6.5. Wie bekomme ich es hin, das der Benutzer in meiner JTable
       keine Eingaben tätigen kann?
       Autor: Alexander Elsholz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das funktioniert über das Tabellenmodell deiner JTable:

import javax.swing.table.DefaultTableModel

/**
 * Diese Klasse repräsentiert das Datenmodell für eine oder mehrere
 * Tabellen
 *
 * Die Zuweisung geschieht über JTable.setModel(new YourTableModel()));
 */
public class YourTableModel extends DefaultTableModel {

    /**
     * aus der API: Returns true if the cell at rowIndex and columnIndex 
     * is editable. Otherwise, setValueAt on the cell will not change the
     * value of that cell.
     */
    public boolean isCellEditable(int row, int column) {
        return false;
    }
}

Dieses Bespiel verhindert das Editieren von zellen in allen Zellen der 
Tabelle, durch Auswerten der Parameter könn aber auch einzelne Spalte, 
Zeilen oder Zellen gesperrt werden.


3.6.6. Wie bekomme ich eine horizontale ScrollBar bei JTable?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);


3.6.7. Wie scrolle ich ans Ende von JTable?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* table.scrollRectToVisible(table.getCellRect(
                            table.getRowCount()-1,-1,true));


3.6.8. Wie verhindere ich ein reordering der Spalten bei JTable?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* table.getTableHeader().setReorderingAllowed(false);


3.6.9. Wie verhindere ich ein Resizen der Spalten bei JTable?
       Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* table.getTableHeader().setResizingAllowed(false);


3.6.10. Wie ändere ich die Hintergrundfarbe von JScrollPane?
        Autor: Linda Radecke
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das geht mit:

* scrollpane.getViewport().setBackground(new Color(....));


3.6.11. Wie kann ich ein JLabel dazu bringen, seinen Hintergrund
        zu füllen?
        Autor: Gerhard Bloch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
JLabel zeichnet (wie die meisten Swing-Komponenten) seinen Hintergrund
nicht, wenn es nicht "opaque" ist (obwohl dies unterschiedliche Dinge
sind).

Loesung:
Fuer *undurchsichtige* Hintergrundfarben funktioniert folgendes:

JLabel l = new JLabel("Text");
l.setOpaque(true);
l.setColor(Color.red);


Diese Loesung funktioniert auch fuer transparente Hintergrundfarben:

public class JLabelWithBackground extends JLabel {
    public JLabelWithBackground(String title) {
        super(title);
    }

    public void paintComponent(Graphics g) {
        if (!isOpaque()) {
            Rectangle vr = getVisibleRect();
            g.setColor(getBackground());
            g.fillRect(vr.x, vr.y, vr.width, vr.height);
        }
        super.paintComponent(g);
    }
}

JLabel l = new JLabelWithBackground("Text");
l.setBackground(new Color(255, 0, 0, 128));


3.7. [APPLET] - Frage zu Java-Applets und ihre Zusammenarbeit
                mit Browsern.
--------------------------------------------------------------

3.7.1. Welche JDK-Version sollte ich für Applets verwenden, die
       möglichst allgemein lauffähig sein sollen?
       Autor: Stefan Menzel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Am besten nicht über 1.1.8.


3.7.2. Wie bekomme ich den Internet Explorer dazu, das Plugin 
       anstelle der integrierten JVM zu benutzen.
       Autor: Stefan Menzel, Aljoscha Rittner, Joachim Sauer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Indem auf der aufrufenden Webseite nicht das <APPLET>, sondern das
<OBJECT>-Tag verwendet wird. Es gibt auf
<URL:http://java.sun.com/products/plugin/1.3/docs/html_converter.html>
einen automatischen Konverter einer Seite zur Benutzung des Plugins.

Mit 1.4 kann auch das APPLET-Tag zusammen mit dem Plugin verwendet 
werden. Dazu findet man nähere Informationenen unter:

<URL:http://java.sun.com/j2se/1.4/docs/guide/plugin/developer_guide/
html_converter_more.html>

Anmerkung: Mit 1.4 kann auch das APPLET-Tag zusammen mit dem Plugin 
verwendet werden. Aber alle, die für JDKs größer 1.2 coden sollten 
ohnehin OBJECT verwenden, da sie mit APPLET (auch mit den neuen Plugins)
auf Browser stoßen können, die zwar glauben es darstellen zu können, 
dann aber kläglich scheitern. Wer für 1.1 programmiert sollte sich wohl 
wirklich noch das APPLET-Tag überlegen.


3.7.3. Was dürfen unsignierte Applets nicht aus Sicherheitsgründen?
       Autor: Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Applets wurden generell stark in ihren Rechten eingeschränkt.
Die genauen Einschränkungen sind von der Virtuellen Maschine,
also Browser / Plugin oder Appletviewer abhängig.

Einem signierten Applet kann man explizit mehr Rechte geben
als das normalerweise der Fall ist. Auch gibt es Unterschiede,
ob das Applet von remote oder vom Filesystem geladen wurde.

Ein von remote geladenes Applet darf in der Regel nicht:

* auf das lokale Filesystem zugreifen
* auf die (System-)Zwischenablage zugreifen
* Socketverbindungen zum lokalen Host aufbauen.
* Socketverbindungen zu dritt-Hosts aufbauen.
* System-properties ändern/setzen
* System-properties lesen ausser:
  java.version, java.vendor,java.vendor.url, java.class.version
  os.name, os.arch, os.version,
  file.separator, path.separator, line.separator
* lokal Programme starten
* lokale Bibliotheken laden
* System.exit(int) aufrufen
* Fenster ohne Warnung öffnen

Signieren heisst, das Applet mit einer verschlüsselten Unterschrift
(Signatur) zu versehen, um diesen mehr Rechte zuzuweisen.

Signieren bedarf einer "vertrauenswürdigen" Person bzw. Institution,
unterschiedlich, je ob das Applet nur in einem Intra- oder im gesamten
Internet betrieben werden soll.

Der Prozess des Signieren-Lassens wurde leider noch zusätzlich
dadurch erschwert, dass man jede Signatur praktisch für jede
Browser-VM extra durchführen mus.

Genaueres siehe:
  <URL:http://java.sun.com/sfaq>
(Dort auch böse Testapplets.)

Zur Java-Security und Codesignierung allgemein siehe:
  <URL:http://www.securingjava.com/toc.html>
  <URL:http://home.iSTAR.ca/~neutron/java.html>

und spezieller:

  <URL:http://www.abim.net/jsw/index.htm>
  <URL:http://www.iw.uni-hannover.de/~ruemper/>
  <URL:http://www.suitable.com/Doc_CodeSigning.shtml>
  <URL:http://developer.netscape.com/docs/manuals/signedobj/signtool/
  index.htm> (umgebrochen)
  <URL:http://java.sun.com/products/plugin/1.2/docs/nsobjsigning.html>
  <URL:http://developer.java.sun.com/developer/onlineTraining/
  Programming/JDCBook/signed.html> (umgebrochen)


3.8. [SERVER] - Frage zu Servlets und anderen Server-
                Implementierungen in Java.
-----------------------------------------------------



3.9. [NONCORE] - Fragen zu Klassen/Packages, die über den Kern der 
                 Sprache  hinausgehen, also Java3D etc.
------------------------------------------------------------------



3.10. [OOP] - Frage bezüglich OOP-Konzepten und Patterns in Java.
----------------------------------------------------------------

3.10.1. Was bedeutet Vererbung im OO-Kontext?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vererbung ist in Java, und natürlich auch in anderen Programmiersprachen,
nur eine Möglichkeit, um das konkrete Problem in den Computer zu 
übertragen. Das Prinzip der Vererbung ist dann anwendbar, wenn zwei 
Objekte in einer ist-ein oder ist eine Art von Beziehung zueinander 
stehen. Eine abgeleitete Klasse ist ein Subtyp der zugehörigen 
Oberklasse, besitzt also deren Eigenschaften (Daten & Methoden) und 
erweitert diese bei Bedarf um neue. LKW und PKW sind zum Beispiel 
Subtypen der Oberklasse Automobil, wobei beim LKW zum Beispiel die 
maximal zulässige Anhängerlast oder die Achsenanzahl hinzukommt.

Wendet man das Prinzip der Vererbung an, so gilt das sogenannte 
Liskov'sche Substitutionsprinzip:

Objekte der abgeleiteten Klasse können stets an die Stelle von Objekten
der Oberklasse treten.


3.10.2. Was bedeutet Aggregation im OO-Kontext?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das Prinzip der Aggregation besagt, daß ein Objekt aus mehreren Teilen
(=Objekten) besteht, die wiederrum aus Teilen bestehen können usw. 
Die Klasse Computer könnte z.B. aus den Klassen Speicher, Festplatte 
etc. bestehen. In einem Pseudo-Java-Code etwa so formuliert:

public class Computer {
    private Speicher rom;
    private Speicher ram;
    private Speicher festPlatte;

    (...)
}


3.10.3. Was bedeutet Assoziation im OO-Kontext?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mit der Assoziation wird die Verbindung des Objektes zu einem oder 
mehreren anderen Objekten beschrieben. Assoziationen können kurzfristig 
sein, zum Beispiel dann, wenn ein anderes Objekt an das aktuelle Objekt 
als Parameter der Objektmethode übergeben wird. Sie können aber auch 
langfristig sein, wenn das Objekt Referenzen auf die assoziierten 
Objekte speichert (Registrierung).


3.10.4. Was bedeutet Benutzung im OO-Kontext?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das aktuelle Objekt benutzt eines oder mehrere andere Objekte um die 
anstehende Aufgabe erfüllen zu können. Das Objekt Backofen benutzt zum 
Beispiel das Objekt Thermostat, um die Aufgabe backen zu erfüllen, damit
der Inhalt des Backofens nicht verkohlt.

Es muß angemerkt werden, daß man häufig aus dem Programmcode keine 
direkte Entscheidung treffen kann, ob Aggregation, Assoziation oder 
Benutzung vorliegt. Diese drei Beziehungen sind prinzipiell 
Designprinzipien, die in der späteren Implementierungsphase, zum 
Beispiel in Java, in relativ ähnliche oder sogar identische Konstrukte 
umgesetzt werden. Es ist deshalb wichtig, daß man das jeweils zugrunde 
gelegte Prinzip dokumentiert, damit die Funktionsweise besser und 
einfacher nachvollzogen werden kann.


3.10.5. Worin liegen die Unterschiede zwischen abstrakten Klassen
        und Interfaces?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java fügt dem schon von C++ her bekannten Konzept der abstrakten Klasse
noch ein weiteres, aus der Sprache Objective-C entliehenes Feature hinzu:
Interfaces. Ein Interface ist zuersteinmal nichts anderes als eine 
Auflistung von Methoden. Eine Klasse implementiert ein Interface, wenn 
sie alle in der Interface-Deklaration angegebenen Methoden besitzt. 
Wird mindestens eine der Methoden des Interfaces nicht implementiert, so
wird die Klasse zu einer abstrakten Klasse. Mit dem Interface-Prinzip 
lassen sich in Java einfach Benutzt-Beziehungen modellieren. Eine Klasse
benutzt eine andere Klasse in dem Sinn, daß es ganz spezielle Methoden 
dieser Klasse verwendet, um seine eigene Funktionalität zu realisieren -
auf Daten der Hilfsklasse wird ja wegen dem Prinzip der Datenkapselung 
nicht direkt zugegriffen. Um ein Objekt zu benutzen, ist es nur wichtig,
daß dieses Objekt die gewünschten Funktionen auch besitzt. Man definiert
sich daher ein Interface, welches die benötigten Funktionen auflistet. 
Alle Objekte, die diese Funktionen benötigen, sprich, die dieses 
Interface verlangen, können nun all die Klassen verwenden, die dieses 
Interface implementieren. Im Sinne eines guten Klassendesigns ist es 
daher wichtig, solche Benutzt-Beziehungen zu lokalisieren, um die 
Klassen flexibler zu machen und unnötigerweise angewendete Vererbung zu 
eliminieren. Abstrakte Klassen sind im Gegensatz dazu Modellierungen 
des Ist ein-Prinzips und unterscheiden sich in dieser Hinsicht von 
Interfaces.


3.10.6. Was ist eine anonyme innere Klasse?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Eine anonyme innere Klasse trägt keinen Namen und wird vor allem bei der
GUI-Programmierung für Adapterklassen verwendet. Wird eine solche Klasse
in ein Class-File übersetzt, so werden alle anonymen Klassen, die in der
umgebenden Klasse definiert wurden, von Null beginnend durhnummeriert.

    Testklasse$0.class

ist also das Class-File der ersten in der Klasse  Testklasse 
auftauchenden anonymen inneren Klasse.


3.10.7. Was ist ein immutable Objekt?
        Autor: Gerhard Bloch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ein immutable (unveraenderliches) Objekt ist ein Objekt, das nach seiner
Instanzierung nicht mehr veraendert werden kann. Bekannte Beispiele
hierfuer sind saemtliche Wrapper-Klassen (Integer, Boolean,... ) sowie
die Klasse String.

Dieses Design-Pattern bietet folgende Vorteile:
+ Instanzen koennen gefahrlos mehrfach referenziert werden
+ keine Synchronisation noetig
+ sehr gut geeignet als Schluessel fuer HashMap

Immutable Objekte muessen folgende Forderungen erfuellen:
+ alle Attribute sind final
+ alle nicht selbst immutable Attribute sind zusaetzlich private
+ kein Schreibzugriff auf Attribute moeglich
+ direkter Lesezugriff ist nur auf selbst immutable Attribute erlaubt
+ im Konstruktor uebergebene mutable Objekte muessen geklont(*) werden

(*) Klonen ist hier in der Bedeutung "tief genug kopieren" gemeint: Es
muessen rekursiv alle mutable Attribute kopiert werden. Dies hoert sich
komplizierter an, als es in der Praxis ist, da die verwendeten Objekte
i.d.R. nicht verschachtelt sind, reicht meist eine flache Kopie aus.


Beispiel:

public class MyImmutable {
    public  final int i;
    private final String s;
    private final int[] a;
    private final Point p;

    public MyImmutable(int i, String s, int[] a, Point p) {
        this.i = i;                  // primitiver Typ ist immutable
        this.s = s;                  // String ist immutable
        this.a = new int[a.length];  // Arrays sind mutable!
        System.arraycopy(a, 0, this.a, 0, a.length);
        this.p = new Point(p);       // Point ist mutable!
    }
    
    public String getS() {
        return s;
    }
    
    // Array ist mutable, also Klon zurueckgeben
    public int[] getA() {
        return (int[]) a.clone();
    }
    
    // alternativ: Elementzugriff, die int-Elemente sind immutable
    public int getAAt(int pos) {
        return a[pos];
    }
    
    // Point ist mutable, also Klon zurueckgeben
    public Point getP() {
        return new Point(p);
    }
}


Zusaetzlich ist folgendes zu beachten:
Subklassen von Immutables muessen selbst nicht immutable sein und
koennen im schlimmsten Fall sogar das Konzept unterlaufen!

Beispiel:

public class AntiImmutable extends MyImmutable {
    public String s;

    public AntiImmutable(int i, String s, int[] a, Point p) {
        super(i, "", a, p);
        this.s = s;
    }

    public String getS() {
        return s;
    }
}

MyImmutable mi = new AntiImmutable(0, "A", anIntArray, new Point(0, 0));
((AntiImmutable)mi).s = "B";
System.out.println(mi.getS());

--> Ergibt "B"!!!

Daher ist es meist angebracht, Immutables final zu deklarieren! Zudem
sollte man Attribute, die zwar immutable, aber nicht final sind, wie
Mutables behandeln (also im Konstruktor bzw. bei der Rueckgabe klonen).


3.11. [JDK] - Frage zu virtuelle Maschinen, alles über JDKs und deren
              Installation und Verwendung.
---------------------------------------------------------------------

3.11.1. Was ist ein Java Development Kit (JDK)
        Autor: Hubert Partl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das JDK ist eine Software, die für die Erstellung, Übersetzung und 
Ausführung von Java-Programmen notwendig ist; enthält unter anderem den 
Java-Compiler, das Java Runtime Environment JRE und diverse 
Hilfsprogramme. Der Name bedeutet übersetzt Java-Entwicklungs-Werkzeug.


3.11.2. Was ist ein Java Runtime Environment (JRE)
        Autor: Hubert Partl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das JRE ist eine Software, die für die Ausführung von Java-Programmen
notwendig ist; enthält unter anderem die Java Virtual Machine JVM und 
die Klassenbibliothek. Der Name bedeutet übersetzt Java-Laufzeit-
Umgebung.


3.11.3. Was ist eine Java Virtual Machine (JVM)
        Autor: Hubert Partl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Die JVM ist eine die Software, die notwendig ist, um ein Java-
Binärprogramm (Bytecode) auf einem Computer auszuführen. Der Name 
bedeutet virtuelle Java-Maschine und kommt daher, dass der Computer, 
der direkt nur Windows- oder Macintosh- oder Unix-Binärprogramme 
ausführen kann, mit Hilfe der JVM so wirkt, als ob er Java-Bytecode 
ausführen könnte, also als ob er eine Java-Maschine wäre.


3.11.4. Wie konfiguriere ich JDK1.3/1.4 unter Linux oder Unix?
        Autor: Martin Erren, Michael Paap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Frage:

Bei meinem Linux ist per default kaffe (jdk1.1.8) eingestellt, obwohl
ich das Sun jdk installiert habe. Wie kann ich 1.3 unter Linux benutzen?

Antwort:

Die default-Einstellungen sind gut für jene, die nur GNU-Lizenzen
akzeptieren, aber schlecht für solche, die ernsthaft in Java entwickln
oder anspruchsvolle Java-Programme benutzen wollen.

I. SuSE Linux

SuSE macht die Umstellung auf das aktuelle Sun-jdk wenigstens einfach.
Sie muss jedoch per Hand erfolgen.

Ein normaler Benutzer hat /usr/lib/java/bin im $PATH.
(Unter root braucht/soll Java nicht gestartet werden)
/usr/lib/java ist ein symbolic link auf /usr/lib/jdk1.1.8,
eine Variante vom jdk 1.1.8 namens kaffe.

Man vergewissere sich dessen mit

# file /usr/lib/java

Falls tatsächlich ein symbolic link, kann man diesen getrost
(unter root) mit

# rm /usr/lib/java

löschen und mit

# ln -s /usr/java/jdk1.3.1_01 /usr/lib/java

auf das Sun jdk neu verlinken. Weiterhin sollte man in /etc/rc.config 
die Variable CREATE_JAVALINK auf "no" setzen, sonst setzt SuSEConfig den
Link wieder in den Urzustand, wenn es das nächste Mal
läuft.

Diese Angaben gelten für SuSE 7.3 und können pro
Distributions-Version geringfügig von der beschriebenen
Struktur abweichen.

(Falls Dir symbolic links, file, rm, $PATH nichts sagen,
solltest Du Dir eine kleine Einführung in UN*X besorgen,
zum Beispiel [...])


II. Unix/Linux Allgemein

Da andere Linux Distributionen nicht so verbreitet sind wie SuSE,
können hier kaum alle Originalkonfigurationen durchgegangen werden.

Bei allen UN*X Varianten kann man aber immer so analysieren:

* Mit "java -version" die installierte JRE überprüfen.
* Mit "type java" erkennen ob "java" ein alias, oder eine ausführbare
  Datei ist, bzw. wo sie im Filesystem liegt.
* Mit "file .../java" erkennen, ob es sich um ein script oder eine
  binary handelt.

Und so zu einem installierten Sun-JDK umlenken ($JAVA_HOME sei das
installierte Sun JDK):

* Den $PATH ändern, Eintrag auf $JAVA_HOME/bin *vor* der Original-
  Binary
* "alias" setzen (hat immer Vorrang).
* Etwaige links umbiegen wie oben beschrieben.

Die Variable $JAVA_HOME sollte man ebenfalls setzen, da einige
Programme so das installierte JDK finden (z.B. Tomcat).


3.11.5. Wie installiere und konfiguriere ich das jdk unter 
        Windows 9x/Me/NT/2000 richtig?
        Autor: Wolfgang Schirmer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Als Referenz-jdk nehmen wir das jdk1.3.1 !
Nach dem Download des jdk 1.3.1 wird die Installationsroutine über den
klick auf die jdk1_3_1-win.exe gestartet. Nach der Begrüssung und den
Auszug aus den Lizenzbedingungen erfolgt die Auswahl des Installations-
verzeichnisses. Standardmässig wird das Verzeichnis C:\jdk1.3.1
vorgeschlagen. Dies kann aber über Browse geändert werden. Nach der
Festlegung des Installationsumfanges werden die Dateien auf die
Festplatte kopiert.

Durch die Eingabe des Kommandos:

java -version 

in der DOS-Box kann festgestellt werden welche Version auf dem System 
installiert wurde. Für dieses Beispiel sollte folgende Nachricht als
Reaktion auf das Kommando erscheinen: 

    java version "1.3.1"
    
Als nächstes sind die PATH-Einstellungen zu überprüfen. Hierbei
ist es wichtig zu wissen, dass die PATH-Anweisung die Pfade festlegt,
in denen das Betriebssystem nach Programmen sucht.

Unter Windows 9x/Me wird die Pfadeinstellung in der autoexec.bat
durchgeführt. Hier sollte die PATH-Zeile folgendermassen aussehen:

    PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;C:\jdk1.3.1\bin

Nach dieser Änderung in der autoexec.bat muss das System neu
gestartet werden, damit die Änderungen auch wirksam werden.

Unter WindowsNT/2000 ist die Pfadeinstellung in der 
Systemsteuerung|System|Umgebung innerhalb der Systemvariablen 
vorzunehmen. Hier ist der Eintrag in der Variablen PATH durch die 
Zuweisung:

    ;C:\jdk1.3.1\bin 

zu ergänzen. Die Änderungen werden erst in den nach der Änderung 
geöffneten DOS-Box wirksam. Achtung! Um unter WinNT/2000 diese 
Einstellungen vornehmen zu können muss man die Administrator-
Berechtigung besitzen.


3.12. [TOOLS] - Frage zu einem Java-Zusatz-Tool, zum Beispiel IDEs, 
                Build-Tools, Profiler, etc.
-------------------------------------------------------------------

3.12.1. Welche IDE muss ich verwenden?
        Autor: Martin Erren
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<URL:http://groups.google.com/groups?q=beste+%2B+IDE+%2B+Java
++-emacs+-vi+-vim+-notepad+group%3Ade.comp.lang.java&hl=de&btnG
=Google-Suche>

BTW: Der Link muss aus den 3 Zeilen zusammengesetzt werden !

Bietet eigentlich jederzeit einen guten Überblick.


3.12.2. Wie kann man eine Java-Anwendung in eine EXE-Datei umwandeln?
        Autor: Marco Schmidt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ein nativer Compiler ist in der Lage, Quelltext oder Bytecode in eine 
native Anwendung (statt wie üblich bei Java in Bytecode, also
.class-Dateien) umzuwandeln, etwa eine EXE-Datei unter Windows.

Auf 

<URL:http://www.geocities.com/marcoschmidt.geo/jcomp.html#nativeproducts>

sind u. a. auch einige native Compiler und weiterführende Links zum
Thema "native compilation" aufgelistet.

Bei der Verwendung gibt es allerdings ein paar Punkte zu beachten.

* Gute native Compiler sind recht teuer und somit nur im
professionellen Umfeld sinnvoll einsetzbar. Der freie native Compiler
gcj unterstützt z. B. nur Java 1.1, und auch das nur teilweise (kein
AWT etc.).

* Obwohl das vom nativen Compiler erzeugte Programm aus nativem Code 
besteht, muß oft trotzdem noch ein Java Runtime Environment
installiert werden, so daß der Vorteil der einfachen Verteilung des
Programms wegfällt - der Benutzer könnte genauso gut direkt das JRE 
installieren und die Bytecode-Version der Anwendung starten.

* Der große Geschwindigkeitsvorteil durch nativen Code existiert
heutzutage nicht mehr, da moderne JVMs durch Just-in-time-Compiler in
den meisten Fällen sehr nah an nativen Code herankommen. In
Einzelfällen mag es aber durchaus Vorteile bei nativem Code geben.

* Da es native Compiler nicht für all diejenigen Plattformen gibt, für
die auch JREs existieren, schränkt man die Anzahl potentieller Nutzer
ein, wenn man auf nativen Code besteht. Allerdings dürften mit nativen
Compilern für Windows und ein paar der verbreiteteren Unix-Varianten
absolut gesehen der größte Teil aller Computerbenutzer abgedeckt sein.

* Wer nativen Code verwendet, muß eventuell mehrere Versionen des
Programms für verschiedene Plattformen pflegen. Durch die Verwendung
von Bytecode (.class-Dateien) hat man eine Version, die überall
ausgeführt werden kann ("write once, run anywhere").

Zum Schluß noch ein paar Vorteile durch die Verwendung eines nativen
Compilers.

* Native Programme starten meist schneller - dies ist für lang
laufende Server-Anwendungen nicht so wichtig, für häufig aufgerufene
Kommandozeilenprogramme allerdings schon eher.

* Es ist schwerer, nativen Code als Bytecode zu dekompilieren (also
wieder den Quelltext zu erhalten). Wer also Reverse-engineering seines
Programms fürchtet, hat bei Bytecode mehr Anlaß zur Sorge.

* Einige native Compiler ermöglichen es, daß gleichzeitig laufende
Instanzen der erzeugten Programme sich gewisse Ressourcen teilen und
so weniger Arbeitsspeicher verbrauchen. Aktuelle JVMs laufen stets
völlig unabhängig voneinander ab (dies wird sich vielleicht nach Java
1.4 ändern).  Man kann mit nativen Anwendungen also mehr Instanzen
eines Programms auf demselben System laufen lassen.

Native Compiler haben in einigen Nischen also durchaus
Daseinsberechtigung. Allerdings sollte, wer sich um einfache
Verteilung seines Programms Gedanken macht, eine der folgenden
Möglichkeiten in Betracht ziehen:

* Suns Java Webstart <URL:http://java.sun.com/products/javawebstart/>

* Ausführbare JAR-Dateien, die sich mit einem Doppelklick auf das 
entsprechende Icon starten lassen
<URL:http://java.sun.com/products/jdk/1.2/docs/guide/extensions/
spec.html#executable>

* Einen Installer wie InstallAnywhere <URL:http://www.zerog.com/>,
JExpress <URL:http://www.denova.com/> oder eines der Produkte aus dem
entsprechenden Abschnitt des Open Directory:
<URL:http://dmoz.org/Computers/Programming/Languages/Java/
Development_Tools/Deployment/>


3.13. [MISC] - Alles, was nicht in eine der anderen Rubriken paßt.
------------------------------------------------------------------
   
3.13.1. Warum rechnet Java falsch?
        Autor: Markus Reitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Problem:

public class Test {
    public static void main(String[] args) {
        float zahl = 0.0F;
        for (int i = 0; i <= 100; i++) {
            System.out.println(zahl);
            zahl += 0.1F;
        }
    }
}

Läßt man obiges Programm laufen so ergibt sich folgende Ausgabe:

    0.0
    0.1
    0.2
    0.3
    0.4
    0.5
    0.6
    0.70000005
    0.8000001
    0.9000001
    ...

Scheinbar rechnet Java an einigen Stellen falsch und ist nicht fähig, 
zu einer Zahl den Wert 0.1 korrekt zu addieren. Dies sieht jedoch nur 
so aus und ist auch keineswegs typisch für die Programmiersprache Java,
sondern ein allgemeines Problem.


Zahlendarstellung im Computer:

Um dies zu verstehen, muß man sich klar machen, daß ganze Zahlen intern
in Form von Binärzahlen und Fließkommazahlen mit Hilfe von Binärbrüchen
dargestellt werden. Nun kann der (nicht gerade seltene) Fall eintreten,
daß sich eine Zahl im Dezimalsystem zwar darstellen läßt, in 
Binärdarstellung jedoch zu einem unendlichen, nicht abbrechenden, Bruch
wird. Für die Speicherung einer Zahl steht aber nur ein beschränkter 
Speicherplatz zur Verfügung, d.h. die unendliche Binärdarstellung wird 
nur bis zu einer gewissen Stelle gespeichert. Das Resultat sind 
Ungenauigkeiten. Addiert man jetzt solche Zahlen (und 0.1 ist ein 
Beispiel für so eine Zahl) mehrfach auf, so addieren sich die 
unvermeidbaren Ungenauigkeiten immer mehr auf und führen zu dem obigen 
Verhalten. Dies ist keineswegs charakteristisch für Java, sondern auch 
in jeder anderen Sprache, die Fließkommazahlen verwendet, 
reproduzierbar. Eine Abmilderung des Problems besteht in einer schlauen 
Rundung von Zwischenergebnissen an geeigneten Stellen der Berechnung, 
so daß Fehler kompensiert oder zumindest abgeschwächt werden.


Runden von Fließkommazahlen:

Wenige Zeilen weiter oben wurde davon gesprochen, mögliche Rechenfehler
auszugleichen, indem man an geeigneten Stellen rundet. Wie aber rundet 
man eine Fließkommazahl? Nun, das Prinzip hat sich seit den Tagen des 
C-64 nicht geändert:

  - Verschiebe das Komma um die gewünschte Anzahl an Stellen nach 
    rechts.
  - Addiere zu der neuen Zahl 0.5 hinzu und schneide die 
    Nachkommastellen ab.
  - Verschiebe das Komma um die selbe Anzahl an Stellen wieder nach 
    links.

Berücksichtigt man, daß das Verschieben des Kommata um n Stellen nach
rechts der Multiplikation der Zahl mit 10^n entspricht und die 
Verschiebung nach links in analoger Weise durch die Division durch 10^n
erledigt wird, kann man die Rundungsfunktion wie folgt formulieren:

double runden(double d) {
    return ((int) z * Math.pow(10, n)) / Math.pow(10, n);
}

Es ist unter anderem auch in Betracht zu ziehen die Klasse 
java.math.BigDecimal zu verwenden, die hier beim Erzeugen einer