Java

Aus m-wiki
Version vom 19. September 2016, 22:35 Uhr von Snoopy78 (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „== Einführung ==\ === Kommentare ===\ * // Kommentar -> Einzeiliger Kommentar\ * →‎Kommentar: -> Mehrzeiliger Kommentar\ * →‎* Kommentar: -> Mehrzeilig…“)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

== Einführung ==\ === Kommentare ===\

  • // Kommentar -> Einzeiliger Kommentar\
  • /* Kommentar */ -> Mehrzeiliger Kommentar\
  • /** Kommentar */ -> Mehrzeiliger Kommentar für Dokumentation\

\ == Dateiaufbau und Bibliotheken/Packages ==\

  • Nur eine Klasse darf pro Datei öffentlich sein und diese muss den Namen der Datei haben\
  • Die Java-Bibliotheken enthalten Packages mit Klassen, Schnittstellen (Interfaces) und Ausnahmebehandlungen (Exceptions)\
  • Externe Bibliotheken werden über die Pfadangabe eingebunden: java.util.Date d = new java.util.Date();\
    • Um alle Klassen eines Paketes / einer Bibliothek einzufügen (und damit Schreibarbeit zu sparen) wird der import-Befehl verwendet: import java.util.*;\
    • Will man nur eine einzelne Klasse eines Paketes importieren (Overhead beim kompilieren reduzieren): import java.util.Date;\
  • Packages kann man selber erstellen auch wieder mit der Angabe des Pfades ab dem Java-Verzeichnis: package Paketname;\
    • Die Angabe package muss immer zuoberst in der Datei stehen (noch vor dem Import), sonst gibt es einen Fehler\
    • Wie bei normalen Klassen darf nur eine Klasse öffentlich sein, welche dann den Dateinamen gibt: \\Tool\\Network\\MyClass.java\

\ == Syntax ==\ === Sonderzeichen ===\

Zeichen Bedeutung\
\\b Backspace\
\\t horizontaler Tabulator\
\\n Zeilenumbruch\
\\f Seitenumbruch\
\\r Wagenrücklauf\
\\" doppeltes Anführungszeichen\
\\' einfaches Anführungszeichen\
\\\\ Backslash\
\\nnn oktaler Code\
\\uxxxx hexadezimaler Code\

\

System.out.print("ProgrammersBase.NET \\u0021");\ \ === Datentypen ===\

Typ Byte Wertebereich Standardwert\
boolean 1 true, false false\
byte 1 - 27 bis 27 0\
short 2 - 215 bis 215 0\
int 4 - 231 bis 231 0\
long 8 - 263 bis 263 0\
float 4 - 3.40282347*1038 bis 3.40282347*1038 0.0\
double 8 - 1.79769313486231570*10308 bis 1.79769313486231570*10308 0.0\
char 2 alle Unicode - Zeichen \\n0000\

\

Diese Datentypen können mit sogenannten Wrapper-Klassen bei Bedarf auch als Objekte verwendet werden. Da mir der Sinn schleierhaft ist, wird das Ganze hier auch nicht weiter behandelt.\ \ === Datentypen umwandeln ===\ Kleine DT werden bei Bedarf automatisch umgewandelt, während man beim umgekehrten Weg einen expliziten Cast anwenden muss, da dabei Werte verloren gehen können.\ Die Zuweisung geschieht mit: (gewünschter Datentyp) Variable\

\
int i = 65;\
char c = (char) i; // -> Nun Buchstabe A\

\

Wichtig: Boolean kann nicht umgewandelt werden in einen Integerwert.\ \ === Variablen ===\ Typ Name = Wert;\ \ ==== lokale Variablen ==== \ Nur innerhalb des definierten Blocks (Schleife) oder der Methode gültig. Wenn nicht über den Rückgabewert zurückgegeben, wird ihr Inhalt beim verlassen verworfen.\ \ ==== konstante Variablen (Konstanten) ==== \ Kann den Wert nach der Definition nicht mehr ändern. Etwa für Pi oder ähnliches verwendet, doch kein Muss.
\

\
final Typ Name = Wert;\
final float pi = 3.14;\

\

Will man die Variable nur einmal pro Klasse brauchen, kann man sie auch auslagern und statisch verwenden.\ \ ==== statische Variablen ==== \ Gleicher Gültigkeitsbereich wie lokale Variablen, doch sie behalten ihren Wert auch über das Ende der Methode hinaus und können beim nochmaligen betreten weiter verwendet werden (Aufrufe zählen (Instanzen usw.)). Das heisst, die Variable bleibt bis zum Programmende oder dem expliziten "zerstören" aller Klasseninstanzen persistent im Speicher.\

\
class Test {  \
  static public int i = 2;       \
} // end class Test\
\
public class MyClass {\
  public static void main(String[] args) {\
    System.out.print(Test.i);      \
  }\
} // end class MyClass\

\

Wie man sieht, muss die statische Variable in eine externe Klasse ausgelagert werden, damit das Ganze auch funktionieren kann. Damit man die Variable auch sieht, muss sie öffentlich (public) definiert sein.\ \ ==== Klassenvariablen ==== \ Alle benutzerdefinierten Variablen, welche jedoch nicht direkt erzeugt werden oder an eine Instanz gebunden sind. -> Genauer beschreiben\ \ ==== Instanzvariablen ====\ Alle von einer Klasse instantiierten und an ein Objekt gebundenen Variablen -> Noch etwas genauer schreiben\ \ === Arrays ===\ Unterscheiden sich optisch durch die Klammern, doch es sind andere Typen, da Arrays aus Klassen gebaut werden.\ \ ==== Arrays definieren und Werte zuweisen ====\

\
int[][] array2 = new int[10][20];\
array2[3][17] = 127;\

\

Man könnte die Klammern bei der Definition auch hinten beim Namen schreiben, doch da die Übergabe eines Arrays an eine Methode auch so geschieht, machen wir es einheitlich. Wie man sieht, sind auch mehrdimensionale Arrays möglich.\ Man kann auch eigene Arrays definieren (es sind ja Klassen) und diese dann jeweils als Elemente behandeln und darauf zugreifen.\ \ ==== Zugriff auf Elemente im Array ====\

\
wert = array[0][3];\

\

Man sieht, dass die Zählung bei Null beginnt. Hier hat man beim zweidimensionalen Array das 4. Element der ersten "Reihe" gewählt.\ \ ==== Arrays kopieren (arraycopy) ====\ Da Arrays Klassen sind, kann man diese nicht einfach mit array2 = array1; kopieren. Sonst zeigen die Zeiger nämlich weiterhin auf array1. Man verwendet daher folgende Methode:\

\
public class MyClass {\
  public static void main(String[] args) {\
    int[] array1 = {0,1,2,3,4};\
    int[]  copy = {0,0,0,0,0};\
\	\	\
    System.arraycopy(array1,2,copy,1,3); // -> Beginne im array array1 an der Position 3 (Index beginnt bei 0) und kopiere dann ins array copy. \
                                         //    Beginne dort an Position 2 und schreibe 3 kopierte Werte rein.\
\	\	\
    for(int i=0; i<copy.length; i++) {\
      System.out.println(copy[i]);\
    } // end for\
  } // end main\
} // end MyClass\

\

\ ==== Wert in Arrays suchen (binarySearch) ====\ Die binäre Suche ist nur dann korrekt, wenn das Array vorher sortiert wurde. Sonst kann es fehlerhafte Resultate geben.\

\
import java.util.*;      \
      \
public class MyClass {\
  public static void main(String[] args) {\
    int[] array = {1,3,5,8};\
    \
    System.out.println(Arrays.binarySearch(array,5));\
    System.out.println(Arrays.binarySearch(array,6));\
  } // end main\
} // end MyClass\

\

Wird nach einem nicht vorhandenen Eintrag gesucht, so wird als Ergebnis der mögliche Einfügungsindex zurückgegeben und nicht die gefundene Indexposition.\ \ ==== Arrays vergleichen (equals) ====\

\
import java.util.*;      \
      \
public class MyClass {\
  public static void main(String[] args) {\
    int[] array1 = {1,2,3,4};\
    int[] array2 = {1,2,3,4};\
    int[] array3 = {4,3,2,1};\
    int[] array4 = {1,2    };\
    \
    System.out.println(Arrays.equals(array1,array1));\
    System.out.println(Arrays.equals(array1,array2));    \
    System.out.println(Arrays.equals(array2,array3));\
    System.out.println(Arrays.equals(array1,array4));\
  } // end main\
} // end MyClass\

\

Hier wird zuerst zwei mal true geliefert und dann zwei mal false, da die Arrays auch mit den Elementen übereinstimmen müssen und nicht nur in der Anzahl. Dies bedeutet, dass Arrays vor dem Vergleichen sortiert sein müssen, falls dies gewünscht ist.\ \ ==== Array mit bestimmtem Wert füllen (fill) ====\ Hier gibt es zwei Möglichkeiten.\ Alle Elemente:\

Arrays.fill(array,2); // füllt das Array mit dem Wert 2

\

Bestimmter Bereich:\

Arrays.fill(array,2,4,1); // füllt das Array von Index 2 bis Index 4 mit dem Wert 1

\

\ ==== Array sortieren (sort) ====\ Hier gibt es wieder zwei Möglichkeiten.\ Alle Elemente:\

Arrays.sort(array); // sortiert das komplette Array

\

Bestimmter Bereich:\

Arrays.sort(array,2,4); // sortiert das Array von Index 2 bis Index 4 aufsteigend

\

\ ==== Arrays an eine Methode übergeben ====\

\
public static void print(int[] a) {\
    for(int i=0;i<a.length;i++) {\
      System.out.print(a[i]);\
    } // end for\
} // end print\

\

Wie man sieht, wird über den Typ angezeigt, dass es ein Array ist.
\ Da Arrays als Referenz übergeben werden, modifiziert man hier im Gegensatz zu Variablen automatisch das Original.\ \ ==== Array zurückgeben ====\ Hier wird einfach der Rückgabewert void angepasst auf das Array und schon ist es bereit:\

\
public static int[] init() {\
  int[] tmp = new int[10];\	\	\
  for(int i=0;i<tmp.length;i++) {\
    tmp[i] = i;\
  } // end for\	\
  return tmp;\
} // end init\

\

\ ==== Länge des Arrays ermitteln (length) ====\

x = array.length;

\

Wird vor allem in Schleifen zum befüllen verwendet:\

\
for(int i=0;i<array.length;i++) {\
  System.out.print(array[i]);\
} // end for\

\

\ === Strings ===\ ==== Definition ====\

  • Wurden als Klasse implementiert. \
  • Wichtigste Einschränkung: Aus Performancegründen gilt die Klasse als konstant und erzeugte Strings können daher nicht mehr angepasst werden.\
  • Strings sind Unicode und brauchen daher keine Zeichensätze.\

Die Erzeugung kann wie eine Variable oder über den Konstruktor der Klasse erfolgen. Man kann aber auch ein Array oder einen vorhandenen String übergeben (Kopie).\

\
public class MyClass {\
  public static void main(String[] args) {\
    char[] array = {'S','t','r','i','n','g',' ','3'};\
\
    String string1 = "String 1";\
    String string2 = new String("String 2");    \
    String string3 = new String(array,0,8); \
    String string4 = new String(string1);\
  } // end main\
} // end MyClass\

\

==== Strings verketten ====\ Durch das verknüpfen mit + kann man Strings verknüpfen. Man kann dabei auch Zahlen mitgeben:\

\
public class MyClass {\
  public static void main(String[] args) {\
    String string1 = "String 1";\
    String string2 = new String("String 2");   \
    String string3 = string1 + string2 + "Test " + "5";\
  } // end main\
} // end MyClass\

\

\ ==== String Länge ermitteln (length) ====\ Wird wie bei Arrays gemacht:\

\
public class MyClass {\
  public static void main(String[] args) {\
    String string1 = "String 1";\
    System.out.println(string1.length());\
  } // end main\
} // end MyClass\

\

\ ==== Zeichen an einer gewissen Position ermitteln (charAt) ====\ Das Zeichen an der gewünschten Position wird ausgegeben. Das erste Zeichen ist wie beim Array an Position 0.\

\
public class MyClass {\
  public static void main(String[] args) {\
    String string1 = "String 1";\
    System.out.println(string1.charAt(3)); // ergibt 'i'\
  } // end main\
} // end MyClass\

\

\ ==== Substring extrahieren (substring) ====\ Will man mehrere Zeichen extrahieren, verwendet man substring. Die Parameter werden immer vom Anfang aus gerechnet, wobei das Zeichen an der Endeposition nicht mehr mit ausgegeben wird.\

\
public class MyClass {\
  public static void main(String[] args) {\
    String string1 = "String 1";\
    System.out.println(string1.substring(1,3)); // ergibt 'tr'\
  } // end main\
} // end MyClass\

\

Ergibt hier ein 'i'.\ \ ==== Strings auf Inhalte prüfen (z.B.:startsWith, equals, compareTo) ====\ Je nach Bedarf kann man folgende Vergleiche machen:\ \

Befehl Bedeutung Beispiel\
equals Exakter Zeichen- und Längenvergleich \
\
String string1 = "TEST";\
String string2 = "Test";\
    \
System.out.println(string1.equals(string2)); // -> false\
System.out.println(string1.equalsIgnoreCase(string2)); // true\
\
equalsIgnoreCase Gross- Kleinschreibung wird ignoriert \
startsWith Der String muss ab der gewünschten Stelle mit der mitgegebenen Sequenz übereinstimmen \
\
String string = "JAVA.ProgrammersBase.NET";\
String search = "NET";\
    \
System.out.println(string.startsWith(search)); // -> false\
System.out.println(string.startsWith(search, 21)); // -> true (Suche beginnt wie immer mit 0)\
\
endsWith Der String muss auf die mitgegebene Sequenz enden \
\
String string = "JAVA.ProgrammersBase.NET";\
String search = "NET";\
    \
System.out.println(string.endsWith(search)); // -> true\
\
compareTo Führt einen lexikalischen Vergleich durch. Dabei werden die Zeichen verglichen sowie die Stringlänge. Endet ein String oder ist ein Zeichen kleiner beziehungsweise größer, so wird ein numerischer Ergebniswert geliefert. Bei Gleichheit gibt es 0. \
\
String string1 =  "CPP.ProgrammersBase.NET";\
String string2 = "JAVA.ProgrammersBase.NET";\
    \
int i = string1.compareTo(string2);\
    \
if(i<0) { \
  System.out.println("Der 1. String ist lexikalisch kleiner"); // kleiner oder Zeichen früher im Alphabet \
} // end if\
else if(i>0) { \
  System.out.println("Der 1. String ist lexikalisch grösser"); // grösser oder Zeichen später im Alphabet \
} // end else if\
else { \
  System.out.println("Die Strings sind lexikalisch gleich"); // identisch \
} // end else\
\
compareToIgnoreCase Wie oben, aber es wird nur die Länge verglichen, da die Zeichen ja ignoriert werden. \
regionMatches Prüft, ob zwei Sequenzen im String übereinstimmen. Bei Bedarf auch mit Gross- Kleinschreibung. \
\
String string1 = "JAVA.ProgrammersBase.NET";\
String search =  "CPP.ProgrammersBase.NET";\
   \
System.out.println(string1.regionMatches(16, search, 15, 4));\
\

Sucht im string1 ab Position 16 und schaut, ob im übergebenen String (search) an Position 15 die nächsten 4 Zeichen übereinstimmen\

\

\ ==== Position eines Zeichens in String finden (indexOf) ====\ Diese Funktionen liefern die Position des ersten oder letzten Vorkommens des gesuchten Zeichens.\

\
String string = "Such mich";\
String search = "mi";\
\
System.out.println(string.indexOf(search)); // liefert 5\

\

Man kann auch eine definierte Startposition mitgeben und so mittels einer Schleife alle Vorkommnisse zählen, indem man die gefundene Position als neue Startposition mitgibt.
\ Will man das letzte Vorkommen finden, verwendet man lastIndexOf.
\ Wird der Wert nicht gefunden, so liefert die Funktion -1 zurück.\ \ ==== Zeichen ersetzen (replace, toLowerCase, toUpperCase) ====\ Da Strings konstant sind, wird der entsprechende String kopiert und das angepasste Resultat zurückgeliefert.\

\
String string = "Hallo";\
System.out.println(string.replace('a','e')); // -> Hello\

\

\ Mit toLowerCase oder toUpperCase wird der komplette String angepasst.\

\
String string = "klein";\
System.out.println(string.toUpperCase()); // Liefert KLEIN\

\

\ ==== Stringbuffer (variable Strings) ====\ Strings sind ja per Definition konstant. Mit einem Stringbuffer kann man aber variable Strings erzeugen. Das bedeutet, dass man diese danach manipulieren kann. Das Ganze geht auch über die vorhandenen Methoden mit Strings, doch die Stringbuffer sind komfortabler. Um das Ganze zu realisieren, wird eine bestimmte Grösse verwendet, welche mit der capacity Methode abgefragt werden kann. Diese Grösse ist aber nur auf Embedded-Systemen mit wenig Speicher relevant. Man kann die neue Buffergrösse manuell mit ensureCapacity(Grösse) setzen.\

Befehl Bedeutung Beispiel\
append Zeichen am Ende anfügen \
\
StringBuffer string = new StringBuffer("Test");\
\
string.append("zusatz");\
System.out.println(string); // -> Testzusatz\
\
insert Hier kann die Einfügeposition selber bestimmt werden \
\
StringBuffer string =  new StringBuffer("Der String");\
    \
string.insert(3, "neue ");\
System.out.println(string); // -> Der neue String\
\
deleteCharAt entfernt das Zeichen an der mitgegebenen Position \
\
StringBuffer string = new StringBuffer("Testi");\
    \
string.deleteCharAt(4);\
System.out.println(string); // -> Test\
\
delete Löscht eine Buchstabensequenz \
\
StringBuffer string = new StringBuffer("Teststring");\
    \
string.delete(4, 6); // An Position 4 beginnen und 6 Zeichen entfernen\
System.out.println(string); // -> Test\
\
setCharAt Ersetzt ein Zeichen an der gegebenen Position \
\
StringBuffer string = new StringBuffer("Tast");\
    \
string.setCharAt(1, "e");\
System.out.println(string); // -> Test\
\
replace Ersetzt eine bestimmte Sequenz mit der Angegebenen. \
\
StringBuffer string = new StringBuffer("Test");\
    \
string.replace(3, 1, "aurus"); // Entfernt 1 Zeichen an Position 3 und fügt die mitgegebene Sequenz ein\
System.out.println(string); // -> Tesaurus\
\
getChars Kopiert einen Bereich in ein Array. \
\
char[] a = new char[20];\
StringBuffer b = new StringBuffer("Teststring");\
b.getChars(4, 9, a, 0); // Kopiert von Position 4 bis Position 9 ins Array a ab Position 0.\
    \
System.out.println(a); // -> string\
\
substring Kopiert eine angegebene Sequenz \
\
StringBuffer string = new StringBuffer("Teststring");\
    \
System.out.println(string.substring(5); // -> string -> Ohne zweiten Parameter, wird bis zum Ende kopiert, sonst nur bis zur zweiten Position\
\

\

\ === Bedingungen und Schlaufen ===\ ==== if then else ====\

\
if(Bedingung 1) {\
  // Anweisungen\
} // end if\
else if (Bedingung 2) {\
  // Anweisungen\
} // end else\
else {\
  // Anweisungen\
}\

\

Die else if Anweisung kann beliebig oft erfolgen. Hier ist aber ein switch meist besser. Das schlussendliche else wird nur aufgerufen, wenn keine Vorherbedingung erfüllt wurde.\ \ ==== switch ====\

\
switch(Parameter) {\
  case Wert1:  // Anweisungen\
  break;\
  case Wert2:  // Anweisungen\
  break;\
  default:     // Anweisungen\
} // end switch\

\

Der Parameter darf nur int sein. Es sind auch keine Wertebereiche möglich. Alle Anwesiungen nach dem case werden ausgeführt bis zum break. Default wird nur ausgeführt, wenn kein anderer Wert zutraf.\ \ ==== while ====\

\
while(Bedingung) {\
  // Anweisungen\
} // end while\

\

  • Solange die Bedingung stimmt, wird durchlaufen\
  • Stimmt die Bedingung schon am Anfang nicht, wird die Schleife übersprungen -> Will man dies nicht, muss man do-while verwenden\
  • Hat man kein oder ein falsches Abbruchkriterium, ergibt sich eine Endlosschleife\

\ ==== for ====\

\
for(Typ Variable = Wert; Bedingung; Update) {\
  // Anweisungen\
} // end for\

\

  • for(int i=0; i<10; i++)\

Kann auch durch eine while-Schleife gebaut werden, ist aber einfacher zu lesen.\ \ ==== Break und Continue ====\

  • break; Abbruch der Schleife\
  • continue; Wiederholung der Schleife\

Continue springt sofort nach der Anweisung wieder zum Kopf und beginnt mit einem neuen Durchlauf. So kann man bei ungültigen Werten gleich den nächsten Wert einlesen. Beim break kann man eine undefinierte Schleife beim Ende der Daten definiert verlassen.\ \ === Operatoren und Operationen ===\ Bei mehreren Operationen in einer Anweisung, werden die Anweisungen entsprechend ihrer Priorität abgearbeitet. Diese Reihenfolge entspricht den mathematischen Regeln. Bei Unsicherheit sollten Klammern eingesetzt werden, da diese dafür sorgen, dass die Reihenfolge entsprechend eingehalten wird.\ \ ==== Mathematik ====\

  • + Führt eine Addition durch.\
  • - Führt eine Subtraktion durch.\
  • * Führt eine Multiplikation durch.\
  • / Führt eine Division durch.\
  • % Führt eine Division durch, wobei nur der Restwert geliefert wird.\

\

  • == Gleichheit (Achtung, Klassen müssen entsprechend ihrer Methoden verglichen werden und dazu gehören auch Arrays)\
  • != Ungleichheit (Siehe Hinweis bei Gleichheit)\

\ ==== inc und dec ====\

  • ++ Erhöht den Wert um 1\
  • -- Erniedrigt um 1\

Je nach Stellung wird zuerst erhöht und dann berechnet oder umgekehrt. Am einfachsten ist der Prefix, doch je nach Verwendung ist auch der Postfix notwendig:\

  • i = j++; // Postfix -> zuerst bekommt i den Wert von j und danach wird j um 1 erhöht.\
  • i = ++j; // Prefix -> zuerst wird j um 1 erhöht und danach i zugewiesen.\

\ ==== Logische Vergleiche ====\

  • ! NICHT // Liefert immer das Gegenteil\
  • && UND mit "Short Circuit Evaluation"\
  • & UND ohne "Short Circuit Evaluation"\
  • || ODER mit "Short Circuit Evaluation"\
  • | ODER ohne "Short Circuit Evaluation"\
  • ^ ODER (exklusiv) // Liefert nur dann TRUE, wenn die Werte unterschiedlich sind (TRUE+FALSE oder FALSE+TRUE) \

\ ===== Short Circuit Evaluation =====\ Verwendet eine Operation dieses Verfahren, so wird der weiter rechts stehende Ausdruck nur dann ausgewertet, wenn er für das Gesamtergebnis noch von Bedeutung ist. Dadurch kann man viele Vergleiche abkürzen.\ \ ==== Bitvergleiche ====\ Auswertung wie oben. Die Vergleiche werden auf die jeweiligen Bits angewendet und nicht auf den gesamten Ausdruck\

  • ~ Komplement // Binäres Komplement bilden: 110 -> 001\
  • & UND // 110 + 101 -> 100\
  • | ODER // 110 + 101 -> 111\
  • ^ ODER (exklusiv) 110 + 101 -> 011\

\ ==== Bits schieben ====\ Die Bits der übergebenen Variable werden um die gewünschte Anzahl verschoben und die füllenden Positionen werden mit 0 gefüllt. Je nach Wahl kann das Vorzeichen belassen werden (pos- / neg.).\

  • << \ Linksverschiebung\
  • >> \ Rechtsverschiebung mit Vorzeichen\
  • >>> \ Rechtsverschiebung ohne Vorzeichen\

\ ==== Spezialabfragen ====\

  • ?: wird als Kurzform eines if then else verwendet. Variable?Truewert:Falsewert; // Lieber sauber mit if then else arbeiten.\
  • instanceof ermittelt, ob der übergebene Wert eine Instanz der angeforderten Klasse oder einer Subklasse davon ist\
  • . wird verwendet, um auf Subklassen und Methoden zuzugreifen (Siehe Kapitel Klassen)\
  • + kann auch Strings miteinander verknüpfen\

\ == Objektorientierung ==\ === Theorie ===\ Das Ziel ist, alle Implementierungsdetails zu kapseln und nur über definierte Schnittstellen (Methoden) mit dem Objekt (Klasse) zu kommunizieren. Wird eine Klasse von einer anderen abgeleitet, so nennt man dies entweder Superklasse -> Subklasse oder Elternklasse -> Kindklasse. Je weiter nach "unten", umso spezifischer wird die Implementierung, während nach oben generalisiert (verallgemeinert) wird.\ Eine Klasse stellt den Bauplan dar, während schliesslich ein Objekt durch eine Instantiierung aus diesem Bauplan erstellt wird.
\ Bevor man sich eine neue Klasse erstellt, sollte man sich die folgenden Fragen stellen (und beantworten), da sich daraus automatisch die Referenz der zu bildenden Klasse ergibt:\

  • Welche Fähigkeiten hat das Objekt? -> Methoden\
  • Welche Eigenschaften hat das Objekt? -> Variablen\
  • Welche Initialisierungen müssen vorgenommen werden? -> Konstruktor(en)\
  • Welche Daten sollen dem Benutzer zugänglich sein? -> Variablen und Methoden intern oder extern zugänglich definieren\
  • (Ist das Objekt Teil einer Vererbungshierarchie?) -> Nur notwendig, wenn mehrere Klassen mit Subklassen geplant werden (Aufteilung)\
  • (Ist das Objekt von anderen Klassen abhängig?) -> Bibliotheken einbinden\

\ ==== Schlagwörter ====\

  • Von Aggregation spricht man, wenn ein Objekt andere aufnehmen kann (Behälter), ohne von ihnen abhängig zu sein. -> is a (a ist b zugeordnet)\
  • Bei der Komposition stellt man das Objekt aus verschiedenen Objekten zusammen und ist somit von den Subobjekten abhängig. -> part of (a ist Teil von b)\

\ ==== Vererbung ====\ In Java kann immer nur von einer Klasse abgeleitet werden, wobei man selber bestimmen kann, welche Eigenschaften man übernimmt und welche man anpasst. Möchte man hingegen Eigenschaften und Methoden von anderen Klassen integrieren, so verwendet man eine Schnittstelle (Interface). Das sind (leere) Methoden einer anderen Klasse, welche dann benutzerspezifisch implementiert werden.\ Alle Klassen werden in Java von Object abgeleitet.\ \ === Klassen ===\ ==== Klasse definieren ====\

\
[public] class Test1 {\
  // Anweisungen\
} // end Test1\

\

Es darf pro Datei nur eine öffentliche Klasse geben und diese muss dem Namen der Datei entsprechen. Hier wäre dies Test1.class. Alle anderen Klassen in der Datei sind automatisch intern, falls noch weitere Klassen definiert werden. Will man eine weitere öffentliche Klasse, so hat man diese in einer eigenen Datei zu speichern.\ \ ==== Klasse verwenden ====\ Die oberhalb definierte Klasse wird folgendermassen eingebunden:\

\
Klasse Anwendung1;\
Anwendung1 = new Test1();\

\

\

\
class MyClass {\
  // Anweisungen\
} // end MyClass\
      \
public class MyTest {\
  public static void main(String[] args) {\
    MyClass object = new MyClass(); // Diesen Befehl könnte man auch aufteilen ins Objekt erstellen und Objekt instantiieren.\
  } // end main\
} // end MyTest\

\

\ ==== innere und anonyme Klassen ====\ Werden verwendet, um eingebundene äussere Klassen kurzfristig für eigene Zwecke zu überschreiben. Sind nur innerhalb der Definition sicht- und verwendbar.\ \ ==== Superklassen und Subklassen (Klassen ableiten) ====\ Die Superklasse ist die Elternklasse oder Basisklasse, von der abgeleitet wird. Die neue Klasse ist die Kind- oder Subklasse:\

\
class MySuperClass{\	\
}\
\
class MySubClass extends MySuperClass{\	\
}\

\

Die Subklasse erbt alle Variablen und Methoden der Superklasse mit Ausnahme der Objekte, welche als final gekennzeichnet wurden. Diese können in der neuen Klasse nicht mehr verändert werden. Zusätzlich werden Konstruktoren und Destruktoren nicht vererbt, da diese klassenspezifisch sind. Genauso statische Methoden, da diese an die jeweilige Klasse gebunden sind und private Variablen, da die der Klasse "gehören".\ Im Gegensatz zu c++ kann man nur immer von einer Klasse ableiten. Alles andere wird über die Schnittstellen "importiert". \ ===== Konstruktoren in abgeleiteten Klassen =====\ Im Konstruktor muss der jeweilige Elternkonstruktor aufgerufen werden (super.Konstruktor();), falls man im Konstruktor Variablen "oberhalb" definieren will (hier die Variable i):\

\
class MySuperClass {\
  public MySuperClass(int i) {\
    this.i = i;\	\
  } // end Konstruktor\
\	\
  public int i;\
} // end MySuperClass\
\
class MySubClass extends MySuperClass {\
  public MySubClass(int i,String s) {\
    super(i);\
    this.s = s;\
  } // end Konstruktor\
\	\
  public String s;\
} // end MySubClass\
\
public class MyClass {\
  public static void main(String[] args) {  \	\
    MySubClass object = new MySubClass(0,"ProgrammersBase.NET");\
\	\	\
    System.out.println(object.i);\
    System.out.println(object.s);\
  } // end main\
} // end MyClass\

\

===== abgeleitete Methoden =====\ Damit abgeleitete Methoden das Verhalten der Basisklasse überschreiben, muss die Originalmethode komplett überschrieben werden (gleiche Parameter und Anzahl). Wählt man nun eine Methode, so wird immer die "tiefste" Stufe genommen, in der eine übereinstimmende Methode gefunden wird. Die direkte Auswahl mittels Punkt ist nur bei der direkten Elternklasse erlaubt und zwar mittels super.methode(). Ohne wird einfach hierarchisch nach oben weiter gesucht, bis es eine entsprechende Methode gibt. Falls keine gefunden wird, kommt es zu einem Fehler.\ \ ===== instanceof (Instanz einer Klasse) =====\ Diese spezielle Methode wird verwendet, um zu prüfen, ob ein Objekt einer bestimmten (abgeleiteten) Klasse oder Schnittstelle entspricht.\

\
System.out.print(object instanceof MyClass);\

\

Damit kann man sicherstellen, dass das gewählte Objekt bestimmten Voraussetzungen entspricht, die man im anschliessenden Code voraussetzt (Methoden, Variablen usw.).\ \ ==== Schnittstellen (Interfaces) ====\ Die Methoden und Variablen müssen öffentlich sein und auch initialisiert. Sie gelten als konstant.\

\
interface MyInterface {\
  public int i = 0;\
  public void print();\
} // end MyInterface\

\

Hier ein Beispiel:\

\
interface MyInterface {\	\
  public String s = "ProgrammersBase.NET";\
  public void print();\
} // end MyInterface\
\
class MyClass implements MyInterface {\
  public void print() {\
    System.out.print(s);\	\
  } // end print\
} // end MyClass\
\
public class MyTest {\
  public static void main(String[] args) {  \	\
    MyClass object = new MyClass();\
    object.print();\
  } // end main\
} // end MyTest\

\

\ Einmal implementierte Schnittstellen werden auch an Subklassen weitergegeben. Das heisst, Subklassen können diese verwenden, ohne diese noch einmal implementieren zu müssen. Bei Bedarf darf man diese aber einfach überschreiben und somit neu definieren.\ Man kann auch mehrere Schnittstellen implementieren. Diese werden jeweils mit Komma getrennt angegeben. Bis jetzt habe ich den Sinn dieser Schnittstellen noch nicht verstanden, da die Methoden ja abstrakt sind und somit jeweils programmiert werden müssen.\ \ === Konstruktoren ===\ Konstruktoren werden erst aufgerufen, nachdem die internen Variablen initialisiert sind. Dies ermöglicht es, die Variablendefinition im Code erst anschliessend zu machen, ohne dass es zu einem Fehler kommt.\ Je nach Vererbungsstatus müssen im Konstruktor noch Variablen der vererbenden Superklassen initialisiert werden.\ ==== Aufbau ====\ Dies sind spezielle Methoden, welche beim erstellen eines Objekts aufgerufen werden, um Werte zu initialisieren. Der Konstruktor ist optional und trägt immer den Namen der Klasse:\

\
class MyClass {\
  public MyClass() {\
    i = 10;\
  } // end Konstruktor\	\	\
  private int i;\
} // end Klasse\

\

\ ==== Parameterübergabe ====\ Da der Konstruktor eine normale Methode ist, können an ihn entsprechende Parameter übergeben werden:\

\
class MyClass {\
  public MyClass(int a, int b) {\
    i = a * b;\
  } // end Konstruktor\
  private int i;\
} // end MyClass\
\
public class MyTest {\
  public static void main(String[] args) {\
    MyClass object = new MyClass(2, 5);\	\	\	\
  } // end main\
} // end MyTest\

\

\ Der Konstruktor kann auch überladen werden, wobei sich entweder die Parameteranzahl oder die Datentypen unterscheiden müssen.\ \ ==== Statische Konstruktoren ====\ Dienen zur Initialisierung der Klassenvariablen. Können keine Parameter bekommen, da der Aufruf zur Laufzeit erfolgt.\

\
class MyClass {\
  public static   int i;\
  public static short s;  \
  static {\
    i = 10;\
    s = 20;\
  } // end Konstruktor\
} // end MyClass\

\

\ === Modifikatoren (public, static usw.) ===\ Java kennt folgende Modifikatoren für Klassen, Methoden, Variablen usw. Diese regeln die Sichtbarkeit und die Lebensdauer.\

Modifikator Sichtbarkeit Lebensdauer Bemerkungen\
public Von überall her (auch externe Klassen). Wird eine Klasse privat markiert, so kann man auch nicht mehr auf interne öffentliche Variablen zugreifen -> wirklich? - -\
protected eigene Klasse und davon abgeleitete Klassen (Alle Klassen des Pakets) - -\
private nur in der eigenen Klasse - -\
package scoped Innerhalb des Pakets sichtbar - Ist theoretisch -> wird intern angewendet, wenn man keinen Modifikator verwendet.\
static - Solange ein Objekt der Klasse existiert. Das Objekt (Variable / Methode) wird über die Klasse (klasse.methode) und nicht über die Instanz (instanz.methode) angesprochen. Dies bedeutet, dass solche Objekte auch nicht abgeleitet werden können, da sie klassenbezogen sind.\
final - - Fixiert den Wert. Variablen können nicht mehr verändert werden und Klassen/Methoden nicht abgeleitet.\
abstract - - Die Methode / Klasse muss in einer abgeleiteten Klasse konkret implementiert werden. In der als abstract definierten Methode oder Klasse werden die Methoden nicht auscodiert. Es werden nur Anweisungen geschrieben, mit welchen Parametern usw. die Methoden schlussendlich arbeiten sollen.
Dies wird etwa bei Schnittstellen verwendet, da diese Methoden dann in anderen Klassen verwendet werden können.\
native - - Sind in einer anderen Sprache wie etwa c++ geschrieben.\
synchronized - - Wird fürs Multithreading verwendet.\
transient - - Diese Objekte werden bei Serialisierung und Deserialisierung ignoriert -> weiter erklären. Normalerweise nicht notwendig.\
volatile - - Stellt Datenintegrität bei Multithreading sicher. Sonst nicht verwendet.\

\

\ === Zugriff auf Variablen ===\ ==== öffentliche Variablen ====\

\
class MyClass {  \
  public int i = 10;\
} // end MyClass\
\
public class MyTest {\
  public static void main(String[] args) {\
    MyClass object = new MyClass();\
    System.out.print(object.i);\
  } // end main\
} // end MyTest\

\

Man sieht, dass die Variable über die Instanz der Klasse angesprochen wird und somit Teil der Instanz ist. Würde man eine zweite Instanz erstellen und den Wert der einen Instanz ändern, so wäre die Variable der zweiten Instanz nicht betroffen.\ \ ==== statische Variablen ====\

\
class MyClass {  \
  public static int i = 10;\
} // end MyClass\
\
public class MyTest {\
  public static void main(String[] args) {\
    System.out.print(MyClass.i);\	\	\
  } // end main\
} // end MyTest\

\

Hier wird keine Instanz gewählt, da man schliesslich unabhängig der Instanzen ist, sondern man greift auf die Klasse selber zu. Das heisst, wenn man diese Variable anpasst, ist diese für alle Instanzen gültig, da es auf die Klasse wirkt (Instanzenzähler). Siehe statische Variablen.\ \ ==== this ====\ Hierbei handelt es sich um einen Verweis auf die eigene Instanz. Möchte man nämlich eine interne Variable ansprechen, so muss das Objekt wissen, dass jetzt die eigene Instanz gemeint ist. Will man etwa aus Unterblöcken auf gleichnamige äussere Variablen der Klasse zugreifen, so kann man dies mit this:\

\
class MyClass {\
  public MyClass(int i,String s) {\
    this.i = i;\
    this.s = s;\
  } // end Konstruktor\
\	\
  private    int i;\
  private String s;\
} // end MyClass\

\

Die Zeile mit dem this.i verweist auf das äussere i, welches sonst vom internen i unsichtbar gemacht worden wäre.\ \ === Methoden ===\ Wie beim Konstruktor gesehen, kann man einer Methode Werte übergeben und auch wieder daraus auslesen.\

\
class MyClass {  \
  public int MyMethod(int a) {\
    System.out.print("Intern: "+a);\
    a++;\	\
    return a;\
  } // end MyMethod\
} // end MyClass\
\
public class MyTest {\
  public static void main(String[] args) {\
    int b = 5;\
    MyClass object = new MyClass();\
    b = object.MyMethod(b);\
    System.out.print("Neu:"+b);\
  } // end main\
} // end MyTest\

\

  • Damit man Werte übergeben kann, muss der Übergabeparameter übereinstimmen -> sonst evtl. Cast notwendig\
  • Ist der Rückgabewert void, so gibt die Methode nichts zurück. Sonst zeigt man an, was zurückgegeben wird\
  • Die Übergabe ist immer als Wert. Ausnahmen bei Arrays und Klassen, da dann ein Zeiger als Referenz übergeben wird\
  • Als Rückgabewert kann auch eine Klasse definiert werden, so dass beliebige Rückgabemengen möglich sind.\
  • Methoden können durch unterschiedliche Parameteranzahl oder Datentypenunterschied überladen werden.\

\ == Fehlerbehandlung (Try-Catch) ==\ === Definition der Fehlerklassen ===\ Wenn ein Fehler im Programmablauf auftritt, so ruft Java spezielle Klassen zur Fehlerbehandlung auf:\

Fehlerart Beschreibung\
Error Diese Klasse repräsentiert die schwersten Fehler im System. Auch wenn sie recht selten auftreten, so ist fortan ein störungsfreier Programmverlauf kaum noch zu garantieren. Subklassen dieser Kategorie sollten nicht selber ausgelöst werden. In der Regel wird bei diesen Fehlern das Programm vollständig beendet. Diese Fehlerklasse wird normalerweise vom System aufgerufen und nicht programmiert.\
Exception Sie ist die wichtigste Hauptkategorie, auf die man sich als Programmierer konzentrieren sollte. Prinzipiell ist auch diese noch einmal zweigeteilt. Und zwar in alle Ausnahmen die von RuntimeException abgeleitet sind oder nicht. Alle benutzerdefinierten Ausnahmen sollten sich in diese Sparte einordnen. \
Runtime Exception Hierbei handelt es sich um Laufzeitfehler, die während des Programmverlaufs auftreten. Die Kategorie vereint alle Fehler, die auf Grund eines Programmierfehlers auftreten können. Dazu gehören unter anderem die folgenden Fälle.\
  • fehlerhafte Typkonvertierung\
  • Zugriff über die Arraygrenze hinaus\
  • Zugriff auf einen leeren Zeiger\

\ Alle nicht von RuntimeException abgeleiteten Klassen repräsentieren Fehler, die sich durch ungünstige Umstände und nicht etwa durch fehlerhaften Code ergeben. Beispiele dafür sind folgende Gegebenheiten.\

  • Fehler beim Lesen einer Datei\
  • ungenügend Systemressourcen\
  • Fehlfunktion externer Dienste\

Je nach Umständen kann das Programm bis auf die aufgerufene Funktion je nach Benutzerentscheid normal weiter laufen.\

\

Der Ablauf ist folgendermassen:\

  • Aufruf des try-Blocks\
  • Fehlerbehandlung, falls notwendig durch catch
    Wird der Fehler nicht abgefangen, wird er schlussendlich durch die generelle Fehlerbehandlung abgefangen, doch dann sieht man meist nur, dass ein Fehler auftrat, doch man kann dann evtl. nicht mehr genau sagen, was passiert ist.\
  • Aufruf des finally-Blocks\

\ === try-catch ===\ Im try-Block wird versucht, eine bestimmte Anweisung auszuführen. Schlägt diese fehl, so wird der catch Block aufgerufen. Hier zeigt sich, dass der Programmierer selbst herausfinden muss, welche Fehler wann auftreten können und wie man diese am besten behandelt.\

\
public class MyClass {\
  public static void main(String[] args) {  \	\
    try {\
      Thread.sleep(2000);\
    } // end try\
    catch(InterruptedException e) {\
      System.out.print("Fehler aufgetreten!");\
    } // end catch\
  } // end main\
} // end myClass\

\

\ Der catch-Block erhält als Parameter die Instanz der auslösenden Fehlerklasse. Dies kann bei der Auswertung hilfreich sein. Bei der Bearbeitung muss man wissen, dass die Klasse von throwable abgeleitet wird und somit schon vordefinierte Methoden enthält, mit welchen man arbeiten kann.
\ \ ==== catch-Typen ====\ Für die Behandlung muss man natürlich wissen, welche Ausnahme ausgelöst wird. Das heisst, es muss bekannt sein, welcher Art Fehler aufgetreten ist. Können mehrere Fehlerarten auftreten, so müssen diese alle aufgeführt werden. Stimmt der Fehlertyp nicht überein, versucht Java, den Fehler in einer höheren Klasse abzufangen. Gelingt dies nicht, so wird das Programm mit einem Runtime-Error beendet.\

\
try {\
  // Anweisungen\
} // end try\
\
catch(Typ1 Objekt) {\
  // Anweisungen\
} // end catch Typ1\
\
catch(Typ2 Objekt) {\
  // Anweisungen\
} // end catch Typ2\

\

\ ==== eigene Fehlerklassen ====\ Möchte man auf "eigene" Fehler reagieren können, so kann man auch eigene Fehlerklassen definieren und diese dann verwenden. Dabei sollte man von Exception ableiten:\

\
class MyException extends Exception {\
  public MyException() {\	\	\
  } // end leerer Konstruktor\
\
  public MyException(String s) {\
    super(s);\	\
  } // end Konstruktor mit string, welcher den Konstruktor von Exception aufruft\
} // end MyException\
\
public class MyClass {\
  public static void main(String[] args) {  \	\
    try {\
      throw new MyException("Fehler aufgetreten..."); // Fehlerbehandlung explizit aufrufen\
    } // end try\
\
    catch(MyException e) { \	\	\
      System.out.print(e.getMessage());\	\
    } // end catch MyException\
  } // end main\
} // end MyClass\

\

\ ==== Fehler ankündigen (throws) ====\ Falls eine Methode einen Fehler (Exception) auslösen könnte (Datei nicht schreibbar usw.), muss dies wegen des Sicherheitskonzepts angekündigt werden, indem man beim erstellen der Methode throws mitgibt und dann die Art des Fehlers. Gibt es verschiedene Fehlerarten, so werden diese komplett mit Komma getrennt aufgelistet. Dazu muss die Methode den problematischen Block jeweils mit try umschliessen.\

\
[Modifikator] Typ Methode() throws Exception1, Exception2, ... {\
  // ....\
  try {\
  // problematische Anweisung\
  } // end try\
} // end Methode\

\

\ ==== finally ====\ Dieser Block ist optional und wird immer aufgerufen, wenn er vorhanden ist. Er wird genutzt, um wichtige Arbeiten auszuführen, auch wenn ein Fehler auftrat (Verbindungen schliessen usw.).\

\
[Modifikator] Typ Methode() throws Exception1, Exception2, ... {\
  // ....\
  try {\
  // problematische Anweisung\
  } // end try\
  catch {\
  // Fehlerbehandlung\
  } // end catch\
  finally {\
  // Schlussblock, welcher immer aufgerufen wird\
  } // end finally\
} // end Methode\

\

\ == Links ==\

Link Beschreibung Niveau\
http://java.programmersbase.net/ Einführung in die Java-Programmierung Anfänger\
http://openbook.galileocomputing.de/javainsel9/ Buch: Java ist auch eine Insel Anfänger-Fortgeschrittene\

\