Modul Einführung in das Programmieren Autoren: Felix Freiling Philipp Klein Friedrich-Alexander-Universität Erlangen-Nürnberg Modul Einführung in das Programmieren Studienbrief 1: Eine Einführung in Programmiersprachen Studienbrief 2: Klassen- und Methodendefinition Studienbrief 3: Kontroll- und Datenstrukturen Studienbrief 4: Vererbung, Polymorphie und Generics Studienbrief 5: Test Driven Development und Debugging Autoren: Felix Freiling Philipp Klein 1. Auflage Friedrich-Alexander-Universität Erlangen-Nürnberg © 2015 Friedrich-Alexander-Universität Erlangen-Nürnberg Lehrstuhl für Informatik 1 IT-Sicherheitsinfrastrukturen Martensstr. 3 91058 Erlangen 1. Auflage (2. März 2015) Das Werk einschließlich seiner Teile ist urheberrechtlich geschützt. Jede Verwendung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung der Verfasser unzulässig und strafbar. Das gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung und Verarbeitung in elektronischen Systemen. Um die Lesbarkeit zu vereinfachen, wird auf die zusätzliche Formulierung der weiblichen Form bei Personenbezeichnungen verzichtet. Wir weisen deshalb darauf hin, dass die Verwendung der männlichen Form explizit als geschlechtsunabhängig verstanden werden soll. Inhaltsverzeichnis Seite 3 Inhaltsverzeichnis Einleitung zu den Studienbriefen I. Abkürzungen der Randsymbole und Farbkodierungen . . . . . . . . . . . . . . . . . . . . . . . II. Zu den Autoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . III. Modullehrziele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Studienbrief 1 Eine Einführung in Programmiersprachen 1.1 Lernergebnisse . . . . . . . . . . . . . . . . . . . . . . 1.2 Advance Organizer . . . . . . . . . . . . . . . . . . . . 1.3 Zahlensysteme . . . . . . . . . . . . . . . . . . . . . . 1.3.1 Was passiert bei einer Addition? . . . . . . . . 1.3.2 Umrechnung ins Binärsystem . . . . . . . . . . 1.3.3 Bits und Bytes . . . . . . . . . . . . . . . . . . 1.3.4 Hexadezimalsystem . . . . . . . . . . . . . . . 1.3.5 Operatoren . . . . . . . . . . . . . . . . . . . . 1.3.6 Negative Zahlen . . . . . . . . . . . . . . . . . 1.3.7 Darstellung gebrochener Zahlen . . . . . . . . 1.3.8 Zusammenfassung . . . . . . . . . . . . . . . 1.4 Opcodes und Assembler . . . . . . . . . . . . . . . . . 1.4.1 Opcodes . . . . . . . . . . . . . . . . . . . . . 1.4.2 Vereinfachung durch Assemblersprache . . . . 1.5 Höhere Programmiersprachen . . . . . . . . . . . . . . 1.5.1 Compiler . . . . . . . . . . . . . . . . . . . . . 1.5.2 Java . . . . . . . . . . . . . . . . . . . . . . . . 1.6 Objektorientierte Programmierung: Ein Beispiel . . . . 1.6.1 Öffnen des Projekts . . . . . . . . . . . . . . . 1.6.2 Klassen . . . . . . . . . . . . . . . . . . . . . . 1.6.3 Methoden . . . . . . . . . . . . . . . . . . . . 1.6.4 Attributwerte . . . . . . . . . . . . . . . . . . . 1.7 Zusammenfassung . . . . . . . . . . . . . . . . . . . . 1.8 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . 1.8.1 Erläuterungen zum Übungsablauf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Studienbrief 2 Klassen- und Methodendefinition 2.1 Lernergebnisse . . . . . . . . . . . . . . . . . . . 2.2 Advance Organizer . . . . . . . . . . . . . . . . . 2.3 IDEs und Texteditoren . . . . . . . . . . . . . . . 2.3.1 Welche Vorteile und Features bieten IDEs? 2.3.2 Welche IDEs gibt es? . . . . . . . . . . . . 2.3.3 Texteditoren . . . . . . . . . . . . . . . . 2.3.4 Worin soll ich Programmieren? . . . . . . 2.4 Was bedeutet Programmieren? . . . . . . . . . . 2.5 Klassendefinition und Attribute . . . . . . . . . . 2.5.1 Schlüsselwort class . . . . . . . . . . . . 2.5.2 Namenskonventionen . . . . . . . . . . . 2.5.3 Attribute . . . . . . . . . . . . . . . . . . 2.6 Methodendefinition . . . . . . . . . . . . . . . . . 2.6.1 Methodenkopf . . . . . . . . . . . . . . . 2.6.2 Methodenrumpf . . . . . . . . . . . . . . 2.7 Einschub: System.out.println() . . . . . . . . . . . 2.8 Variablen . . . . . . . . . . . . . . . . . . . . . . 2.8.1 Casting . . . . . . . . . . . . . . . . . . . 2.8.2 Operatoren bei Zahlen . . . . . . . . . . 2.8.3 Operatoren bei Strings . . . . . . . . . . 2.8.4 Der Modulo-Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 6 7 8 13 13 13 13 14 16 16 18 19 23 25 30 31 31 31 32 34 34 36 36 36 37 38 40 42 42 47 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 47 48 48 49 49 50 50 51 52 52 53 56 56 58 58 59 61 62 62 63 Seite 4 Inhaltsverzeichnis 2.8.5 Auswertungsreihenfolge . . . . . . 2.8.6 Inkrement und Dekrement . . . . . 2.8.7 Anlegen von Objekten . . . . . . . . 2.8.8 Aufrufen von Methoden . . . . . . . 2.8.9 Rückgabe von Werten . . . . . . . . 2.8.10 Kopieren von Objekten . . . . . . . 2.8.11 Gültigkeitsbereich von Variablen . . 2.8.12 Standardwerte und der Wert null . Die main-Methode . . . . . . . . . . . . . . Konstruktoren . . . . . . . . . . . . . . . . . 2.10.1 Definition von Konstruktoren . . . . 2.10.2 Der Default-Konstruktor . . . . . . . Statische Methoden . . . . . . . . . . . . . 2.11.1 Definition von statischen Methoden 2.11.2 Unterschied zu Instanzmethoden . . Zusammenfassung . . . . . . . . . . . . . . Beispiel . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Studienbrief 3 Kontroll- und Datenstrukturen 3.1 Lernergebnisse . . . . . . . . . . . . . . . . 3.2 Advance Organizer . . . . . . . . . . . . . . 3.3 Pakete . . . . . . . . . . . . . . . . . . . . . 3.3.1 Pakete definieren . . . . . . . . . . 3.3.2 Pakete einbinden . . . . . . . . . . 3.3.3 Sichtbarkeiten . . . . . . . . . . . . 3.3.4 Framework und API . . . . . . . . . 3.3.5 Die Java-API . . . . . . . . . . . . . 3.4 Kontrollstrukturen . . . . . . . . . . . . . . 3.4.1 if-Statements . . . . . . . . . . . . 3.4.2 switch-Statements . . . . . . . . . 3.4.3 for-Schleife . . . . . . . . . . . . . 3.4.4 while-Schleife . . . . . . . . . . . . 3.5 Datenstrukturen . . . . . . . . . . . . . . . 3.5.1 Arrays . . . . . . . . . . . . . . . . 3.5.2 ArrayList . . . . . . . . . . . . . . . 3.5.3 HashMap . . . . . . . . . . . . . . . 3.6 Zusammenfassung . . . . . . . . . . . . . . 3.7 Beispiele . . . . . . . . . . . . . . . . . . . 3.8 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Studienbrief 4 Vererbung, Polymorphie und Generics 4.1 Lernergebnisse . . . . . . . . . . . . . . . . . . . . 4.2 Advance Organizer . . . . . . . . . . . . . . . . . . 4.3 Vererbung . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Warum Vererbung? . . . . . . . . . . . . . 4.3.2 Oberklassen und Unterklassen . . . . . . . 4.3.3 Abstrakte Klassen . . . . . . . . . . . . . . 4.3.4 Überschreiben von Methoden . . . . . . . . 4.3.5 Polymorphie . . . . . . . . . . . . . . . . . 4.3.6 Mehrfachvererbung . . . . . . . . . . . . . 4.4 Interfaces . . . . . . . . . . . . . . . . . . . . . . . 4.4.1 Definition . . . . . . . . . . . . . . . . . . . 4.4.2 Einbinden von Interfaces . . . . . . . . . . 4.4.3 Beispielanwendungen . . . . . . . . . . . . 4.4.4 Vererbung vs. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.9 2.10 2.11 2.12 2.13 2.14 63 64 65 65 66 68 69 70 71 72 73 74 76 76 77 78 78 80 85 85 85 85 86 87 87 92 92 92 93 99 101 103 104 104 109 112 114 115 116 121 121 121 121 121 122 125 126 129 132 132 132 132 133 135 Inhaltsverzeichnis 4.5 4.6 4.7 4.8 Seite 5 Generics . . . . . . . . . . 4.5.1 Definition . . . . . 4.5.2 Einschränkungen Zusammenfassung . . . . Beispiel . . . . . . . . . . Übung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Studienbrief 5 Test Driven Development 5.1 Lernergebnisse . . . . . . . . . . . . 5.2 Advance Organizer . . . . . . . . . . 5.3 Debugging und Refactoring . . . . . 5.4 Test Driven Development (TDD) . . . 5.5 JUnit . . . . . . . . . . . . . . . . . . 5.6 Zusammenfassung . . . . . . . . . . 5.7 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . und Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anhang A. Beispiel: User . . . . . . . . . . . . . . . . . A.1 Anforderungen . . . . . . . . . . . . A.2 Vorüberlegungen . . . . . . . . . . A.3 Implementierung . . . . . . . . . . B. Beispiel: User (Fortsetzung) . . . . . . . . . B.1 Anforderungen . . . . . . . . . . . . B.2 Vorüberlegungen . . . . . . . . . . B.3 Implementierung . . . . . . . . . . C. Beispiel: Summe aller Werte in einer Matrix C.1 Anforderungen . . . . . . . . . . . . C.2 Vorüberlegungen . . . . . . . . . . C.3 Implementierung . . . . . . . . . . D. Beispiel: Verkaufsautomat . . . . . . . . . . D.1 Anforderungen . . . . . . . . . . . . D.2 Vorüberlegungen . . . . . . . . . . D.3 Das User-Interface . . . . . . . . . . D.4 Implementierung . . . . . . . . . . D.5 Verbesserungen und Ausblick . . . . E. Beispiel: Eigene ArrayList-Klasse . . . . . . E.1 Anforderung . . . . . . . . . . . . . E.2 Vorüberlegungen . . . . . . . . . . E.3 Implementierung . . . . . . . . . . E.4 Verbesserungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 145 145 145 146 146 146 147 153 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste der Lösungen zu den Kontrollaufgaben Verzeichnisse I. Abbildungen . . II. Beispiele . . . . III. Definitionen . . . IV. Exkurse . . . . . V. Kontrollaufgaben VI. Tabellen . . . . . VII. Literatur . . . . . 136 136 138 139 140 141 154 154 155 156 159 159 159 160 165 165 165 165 167 167 167 171 172 178 179 179 179 179 182 183 187 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 187 187 188 188 189 189 Seite 6 Einleitung zu den Studienbriefen Einleitung zu den Studienbriefen I. Abkürzungen der Randsymbole und Farbkodierungen Beispiel B Definition D Exkurs E Kontrollaufgabe K Quelltext Q Übung Ü Zu den Autoren Seite 7 II. Zu den Autoren Felix Freiling ist Inhaber des Lehrstuhls für IT-Sicherheitsinfrastrukturen an der Friedrich-Alexander-Universität Erlangen-Nürnberg. Schwerpunkte seiner Arbeitsgruppe in Forschung und Lehre sind offensive Methoden der IT-Sicherheit, technische Aspekte der Cyberkriminalität sowie digitale Forensik. Philipp Klein ist seit November 2013 wissenschaftlicher Mitarbeiter am Lehrstuhl für IT-Sicherheitsinfrastrukturen unter der Leitung von Prof. Dr. Felix Freiling. Im Oktober 2013 erhielt er seinen Abschluss Master of Science in Informatik an der Friedrich-Alexander-Universität Erlangen-Nürnberg. Während des Masterstudiums legte er seinen Schwerpunkt auf das Thema IT-Sicherheit. Er besitzt einen Bachelor-Abschluss im Fach Wirtschaftsinformatik der Georg-Simon-OhmHochschule Nürnberg. Seite 8 Einleitung zu den Studienbriefen III. Modullehrziele In dieser Lehrveranstaltung lernen Sie, die Programmiersprache Java zu nutzen, um selbstständig Programme zu schreiben. Nach Lektüre dieses Moduls sind Sie in der Lage, die meisten Programmieraufgaben, die an Sie gestellt werden, zu lösen. Sollten Sie ein bestimmtes Konstrukt der Sprache noch nicht gelernt haben, so können Sie es sich selbstständig in kurzer Zeit aneignen. Darüber hinaus können Sie sich weitere Programmiersprachen selbstständig aneignen. Die Prinzipien und Strukturen, die Sie in dieser Lehrveranstaltung erlernen, finden Sie in den meisten anderen Programmiersprachen wieder. Java bietet dabei einen guten Startpunkt, sowohl hardwarenähere Sprachen als auch beispielsweise Skriptsprachen zu erlernen. Programmieren ist etwas, das man weniger aus Büchern lernt, sondern anwenden und beherrschen muss. Aus diesem Grund sind im Studienbrief viele Kontrollaufgaben, die Sie bearbeiten können. Die Lösungen finden Sie am Ende des Studienbriefs. Darüber hinaus müssen Sie Übungsaufgaben bearbeiten, die Sie am Ende jedes Studienbriefs finden. Das Bearbeiten dieser Aufgaben ist Pflicht, sodass Sie gezwungen sind, wirklich zu programmieren. Gleichzeitig bietet das Abgabesystem aber genug Freiheit, um sich die Zeit selbstständig einzuteilen. Dieses Modul teilt sich in zwei Lehrveranstaltungen auf. In dieser Lehrveranstaltung erlernen Sie die Grundlagen von Java und des Programmierens. In der zweiten Lehrveranstaltung werden einzelne Aspekte von Java genauer betrachtet sowie die Theorie hinter der Programmierung erklärt. In Studienbrief 1 wird zunächst das Dualsystem, dass die Grundlage einer Programmiersprache darstellt, betrachtet. Sie lernen, wie Zahlen im Dualsystem dargestellt und verrechnet werden können und welche Sprache ein Computer spricht. Am Ende dieses Studienbriefs lernen Sie interaktiv die Programmiersprache Java kennen. In Studienbrief 2 werden Sie erstmals selbst Programmcode schreiben. Sie erlernen den allgemeinen Aufbau von Klassen und Methoden. Studienbrief 3 geht näher auf das Innenleben von Methoden ein. In diesem Studienbrief erlernen Sie Kontrollund Datenstrukturen, durch die Sie komplexen Code schreiben können. Nach diesem Studienbrief ist Ihre „Grundausbildung“ im Programmieren abgeschlossen. In den folgenden Studienbriefen verfeinern Sie dann Ihr Wissen. In Studienbrief 4 lernen Sie wichtige Konzepte der objektorientierten Programmierung kennen. Mit Vererbung können Sie Attribute und Methoden vererben. Über Interfaces können Sie versprechen geben, was Ihre Klasse alles kann. Mittels Generics legen Sie sich nicht fest, was für Daten Ihre Klassen speichern können. Der 5. Studienbrief bildet den Abschluss dieser Lehrveranstaltung. Dieser Studienbrief unterscheidet sich stark von den vorherigen, da hier hauptsächlich theoretisches oder sehr spezielles Wissen vermittelt wird. Aus diesem Grund lernen Sie den Großteil des Stoffs nicht aus diesem Studienbrief, sondern aus Videos. Zusätzlich zu den Videos werden Zusammenfassungen des Stoffs angeboten, die Ihnen als Lernstütze helfen sollen. Dieser Studienbrief baut zu Beginn auf dem Buch Java lernen mit BlueJ von Barnes and Kölling [2013] auf, entfernt sich dann aber immer mehr von dem Buch. Trotzdem kann dieses Buch, so wie viele andere Bücher, anstelle dieses Studienbriefs genutzt werden, da alle dasselbe Wissen vermitteln. Nutzen Sie die Materialien, mit denen Sie am besten zurechtkommen. Als Nachschlagewert kann das Buch Handbuch der Java-Programmierung von Krüger and Stark [2009] empfohlen werden. Wenn Sie eine lockere, witzige Herangehensweise an das Thema bevorzugen, können Sie das Buch Java von Kopf bis Fuss von Sierra and Bates [2006] ausprobieren. Zu Test Driven Development in Java empfehlen wir das Buch Test Driven: Practical TDD and Acceptance TDD for Java Developers von Koskela [2007]. Modullehrziele Seite 9 Modulbeschreibung Modulbezeichnung: Grundlagen der Programmierung Studiengang: Bachelor IT-Sicherheit Verwendbarkeit: Dieses Modul ist verwendbar für • Studierende der Informatik • Studierende der Wirtschaftsinformatik • Studierende der Mathematik und Informatik auf Bachelorniveau. Dieses Modul kann nicht als Wahlpflichtmodul gewählt werden, sondern ist ein Pflichtmodul. Lehrveranstaltungen und Lehrformen: Einführung in das Programmieren Programmierkonzepte Modulverantwortliche(r): Prof. Dr. Felix Freiling Lehrende: Prof. Dr. Felix Freiling Dauer: 2 Semester Credits: 10 ECTS Studien- und Prüfungsleistungen: Schriftliche Prüfung: 120 Minuten Um zur Prüfung zugelassen zu werden, müssen die bereitgestellten Übungsaufgaben in jeder Lehrveranstaltung zu mindestens 70% richtig bearbeitet werden. Berechnung der Modulnote: Notwendige Voraussetzungen: Empfohlene Voraussetzungen: Keine Unterrichts- und Prüfungssprache: Deutsch Zuordnung des Moduls zu den Fachgebieten des Curriculums: Einordnung ins Fachsemester: Ab Studiensemester 1 Generelle Zielsetzung des Moduls: Modul zur Förderung und Verstärkung der Fachkompetenz Seite 10 Arbeitsaufwand bzw. Gesamtworkload: Einleitung zu den Studienbriefen Für dieses Modul: Präsenzzeit: 60 h • Vorlesungsteil: 20 h • Übungsteil: 10 h • Praktischer Teil: 20 h • Prüfungsvorbereitungsveranstaltung: 8 h • Prüfung: 2 h Eigenstudium: 240 h • Durcharbeiten der Studienbriefe: 100 h • Wahrnehmen der Online Betreuung und Beratung: 20 h • Ausarbeiten von Aufgaben: 100 h • Individuelle Prüfungsvorbereitung der Studierenden: 20 h Modullehrziele Lerninhalt und Niveau: Seite 11 Einführung in das Programmieren Eine Einführung in die Programmiersprache Java. Mit Hilfe der Entwicklungsumgebung BlueJ wird den Studierenden der Umgang mit Java und Objektorientierung vertraut gemacht. Themen sind unter anderem: • Ausdrücke und Algorithmische Kernsprache von Java • Sprachbeschreibung und Objekttypen • Eine Einführung in bereits existierende Methoden und Klassen in der Programmiersprache Java • Testen und Test Driven Development mit JUnit Darüber hinaus erhalten die Studierenden einen praktischen Einblick in die folgenden programmierrelevanten Technologien/Techniken: • Versionsverwaltung mit Git • Modellierung mit UML Programmierkonzepte Diese Lehrveranstaltung knüpft nahtlos an die Veranstaltung „Einführung in das Programmieren“ an. Die Studierenden lernen weitere Komponenten der Programmiersprache Java kennen, wie beispielsweise: • Exceptionhandling • I/O-Verarbeitung • Hauptspeichermanagement • Krypto-/Security-Klassen • Einbinden von Datenbanken Neben diesen Inhalten lernen die Studierenden ebenso theoretische Grundlagen der Programmierung kennen, wie die Laufzeitanalyse und die Korrektheit von Algorithmen. Das Niveau der Lerninhalte liegt gemessen am DQR-Niveau bei 6 (Bachelor) Seite 12 Angestrebte Lernergebnisse: Einleitung zu den Studienbriefen Fachkompetenz: Die Studierenden können beliebige Programme in Java erstellen. Sprachkomponenten, die Sie noch nicht kennen, können Sie sich in kürzester Zeit aneignen. Zudem sind die Studierenden in der Lage, sich selbstständig neue Programmiersprachen beizubringen. Sie schreiben sichere Programme und wissen, wo potenzielle Schwachstellen in einem Programm zu finden sind. Methodenkompetenz: Die Studierenden beherrschen den Umgang mit beliebigen IDEs. Sie können fremde Programme untersuchen und den Kontrollfluss nachvollziehen. Sie sind in der Lage, Schwachstellen und Fehler in einem Programm zu finden und zu beseitigen. Sozialkompetenz: Durch das gemeinsame Lösen von Aufgaben erlangen die Studierenden die Fähigkeit, eigene Handlungsziele mit den Einstellungen und Werten einer Gruppe zu verknüpfen und ihre Teamfähigkeit zu stärken. In der Präsenzphase erlangen sie u. a. durch Pair-Programming die Kompetenz, eigene Ideen gegenüber einem anderen Programmierer zu kommunizieren, Kompromisse zu bilden und diese im Team umzusetzen. Selbstkompetenz: Die Studierenden erlangen die Fähigkeit zur Bildung einer Meinung über eigene Programme und Programme anderer. Darüber hinaus erlangen sie die Fähigkeit, in komplexen Situationen zu handeln und eine Lösung für komplexe Probleme zu finden. Häufigkeit des Angebots: Wintersemester Anerkannte Module: Anerkannte anderweitige Lernergebnisse / Lernleistungen: Medienformen: Literatur: Studienbriefe in schriftlicher und elektronischer Form, Onlinematerial in Lernplattform, Übungen und Projekt über Lernplattform, Online-Konferenzen, Chat und Forum, Präsenzveranstaltung mit Rechner und Beamer • IT-Sicherheit, Claudia Eckert, 2012 • Java lernen mit BlueJ, David J. Barnes, Michael Kölling, 2013 • Weitere Literatur wird in der Lehrveranstaltung bekannt gegeben. Studienbrief 1 Eine Einführung in Programmiersprachen Studienbrief 1 Eine Einführung in Programmiersprachen 1.1 Lernergebnisse Dieser Studienbrief gibt Ihnen einen Überblick darüber, wie man mithilfe einer Programmiersprache mit einem Computer kommuniziert. Am Ende dieses Studienbriefs wissen Sie, was genau eine Programmiersprache ist. Sie sind mit verschiedenen Zahlensystemen vertraut und können demzufolge Zahlen und unterschiedliche Zahlensysteme darstellen und interpretieren. Sie kennen einige Operationen, die auf binäre Zahlen angewandt werden können. Darüber hinaus verstehen Sie, wie das Dualsystem mit Programmiersprachen zusammenhängt. Des Weiteren haben Sie bereits erste Erfahrungen mit der Programmiersprache Java sowie der IDE BlueJ gesammelt. Sie kennen bereits den Unterschied zwischen Klassen und Objekten und wissen, was Methoden und Parameter sind. 1.2 Advance Organizer Um zu verstehen, was eine Programmiersprache ist, muss zunächst verstanden werden, wie ein Computer generell arbeitet. Aus diesem Grund betrachten wir in diesem Studienbrief das Binärsystem detailliert. Das Grundwissen, dass in diesem Studienbrief behandelt wird, hilft Ihnen, Programmiersprachen und speziell Java besser zu verstehen. Das Wissen, das Sie erwerben, wird Sie in Ihrem gesamten Informatik-Studium begleiten. Bei objektorientierten Programmiersprachen ist es zudem wichtig, den Unterschied zwischen einem Objekt und einer Klasse zu kennen. Durch ein interaktives Tutorial am Ende dieses Studienbriefs werden Ihnen diese Kenntnisse vermittelt. Dies dient der Vorbereitung auf den nächsten Studienbrief, in dem Sie selbst Quellcode schreiben müssen. 1.3 Zahlensysteme Ein Computer (oder besser: der Prozessor/die CPU) versteht keine normale menschliche Sprache. Wenn Sie ihm sagen „Rechne 1+1“, passiert vermutlich zunächst einmal gar nichts. Wenn Sie den Befehl in eine Datei schreiben, wird ebenso nichts passieren. Ein Computer versteht im Grunde nur 0en und 1en. Ein Befehl an den Computer muss daher mit eben diesen 0en und 1en ausgedrückt werden. Diese Art von Sprache wird auch Maschinensprache genannt. Sie basiert auf dem Binär- oder Dualsystem, das wir auf den nächsten Seiten näher betrachten werden. Im alltäglichen Leben rechnen wir im Dezimalsystem. Um sich vor Augen zu führen, was das genau bedeutet, betrachten wir die Zahl 109 (Einhundertneun). Diese Zahl besteht aus 3 Dezimalstellen: Einer, Zehner und Hunderter. Jede Dezimalstelle kann 10 verschiedene Werte annehmen: Die Werte von 0 bis 9. Aus diesem Grund bezeichnen wir dieses System als Dezimalsystem. Die Zahl 10 wird auch als Basis bezeichnet. Die Basis kann bei einer Zahl abgesetzt dahinter geschrieben werden: 10910 . Eine weitere gängige Kennzeichnung einer Dezimalzahl ist ein abgesetztes „d“ hinter der Zahl: 109d . Neben dem Dezimalsystem gibt es aber theoretisch unendlich viele andere Zahlensysteme, die eine andere Basis besitzen. Relevant sind lediglich einige Wenige: Das Seite 13 Seite 14 Studienbrief 1 Eine Einführung in Programmiersprachen Zahlensystem zur Basis 2 (auch Binärsystem oder Dualsystem), das System zur Basis 8 (Oktalsystem), zur Basis 10 (Dezimalsystem) und zur Basis 16 (Hexadezimalsystem). D Definition 1.1: Zahlensysteme Ein Zahlensystem zur Basis n kann pro Stelle die Zahlen 0 bis n − 1 darstellen. Bei den Zahlensystemen, mit denen wir uns beschäftigen, handelt es sich um polyadische Zahlensysteme. In einem polyadischen Zahlensystem hängt der Wert einer Ziffer von seiner Position bzw. Stelle ab. Was das bedeutet, wird deutlich, wenn wir uns wiederum die Zahl 109 ansehen. Obwohl die 1 an der zweiten Stelle (wir beginnen rechts mit Null zu zählen) vom Betrag her eindeutig kleiner ist als die 9 an der nullten Stelle, ist ihr Wert jedoch höher. Um den Wert w der gesamten Zahl zu erhalten, müssten wir Folgendes tun: w(109) = 1 · 102 + 0 · 101 + 9 · 100 = 109 Im Dezimalsystem ist dies natürlich trivial, da wir die Zahl, wenn wir sie sehen, sofort mit der korrekten Wertigkeit aussprechen. Theoretisch müsste man obere Zeile so lesen: „Der Wert der Zahl Eins-Null-Neun ist Einhundertneun“. Die obere Formel lässt sich verallgemeinert auf jedes Zahlensystem anwenden, wie Definition 1.2 zeigt. D Definition 1.2: Wertigkeit einer Zahl Der Wert einer Zahl an . . . a2 a1 a0 zur Basis b, wobei an die Ziffer mit dem Wert a an der n-ten Stelle der Zahl ist, wird folgendermaßen berechnet: w(an . . . a2 a1 a0 ) = an · bn + · · · + a2 · b2 + a1 · b1 + a0 · b0 1.3.1 Was passiert bei einer Addition? Um zu verdeutlichen, wie eine Zahl in einem anderen Zahlensystem (speziell im Binärsystem) ausgedrückt wird, betrachten wir zunächst, was bei einer Addition im Dezimalsystem passiert. Wenn wir die Zahl 109 um eins erhöhen, passiert folgendes: Da die maximal darstellbare Zahl im Dezimalsystem die 9 ist, wird diese Zahl auf 0 gesetzt. Dafür wird die nächsthöhere Dezimalstelle um eins erhöht. Wir sprechen auch von einem sogenannten „Übertrag“. Das Ergebnis ist die Zahl 110. Wie verhält es sich nun, wenn wir nicht zur Basis 10, sondern zur Basis 2 rechnen? Wir können nur die Ziffern 0 und 1 pro Binärstelle darstellen. Wir nennen eine Binärstelle auch „Bit“. Betrachten wir folgende binäre Zahl: 02 . Die binäre Null entspricht der dezimalen Null. Wenn wir zu dieser Zahl eins hinzuaddieren, ist das Ergebnis 12 . Wenn wir diese Zahl wiederum um eins erhöhen, passiert Folgendes: Da das nullte Bit (wie bei Dezimalzahlen steht die niederwertigste Ziffer ganz rechts) bereits den Wert eins hat, kommt es zu einem Überlauf. Das nullte Bit hat nun wieder den Wert 0, das erste Bit wird durch Übertrag um eins erhöht. Das 1.3 Zahlensysteme Seite 15 Ergebnis ist also: 102 . Dies entspricht der Dezimalzahl 2, da 1 + 1 = 2. Bei weiterer Addition von 1 ist das Ergebnis 112 , darauf folgt 1002 usw. Wie ist nun bspw. der dezimale Wert der Zahl 01102 ? Ganz offensichtlich kann es sich nicht um die Zahl Einhundertzehn handeln. Zur Umrechnung benutzen wir die Formel, die wir in Definition 1.2 kennengelernt haben. 01102 = 0 · 23 + 1 · 22 + 1 · 21 + 0 · 20 = 410 + 210 = 610 Die binäre Zahl 01102 entspricht also dem dezimalen Wert 5. In Tabelle 1.1 können Sie für die Dezimalzahlen 0 bis 7 die entsprechenden Zahlen im Dualsystem betrachten. Dezimal 0 1 2 3 4 5 6 7 Binär 0000 0001 0010 0011 0100 0101 0110 0111 Kontrollaufgabe 1.1: Umrechnung ins Dezimalsystem Rechnen Sie folgende binäre Zahlen ins Dezimalsystem um: • 11001100 Tabelle 1.1: Dezimalzahlen und ihre Entsprechung im Binärsystem K • 11111111 • 00000001 • 10000000 Kontrollaufgabe 1.2: Oktalsystem Rechnen Sie folgende Zahlen, die sich im Oktalsystem (Basis 8) befinden, ins Dezimalsystem um: • 0010 K • 7777 • 4706 • 6403 Kontrollaufgabe 1.3: Zweierpotenzen Prägen sie sich die Zweierpotenzen von 20 bis 210 ein. Sie werden sie häufig brauchen. 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 K Seite 16 Studienbrief 1 Eine Einführung in Programmiersprachen 1.3.2 Umrechnung ins Binärsystem Wir sind nun also in der Lage, Zahlen aus dem Binärsystem ins Dezimalsystem umzurechnen. Wir sieht es andersherum aus? Wir wollen die Zahl 11010 im Binärsystem darstellen. Dazu teilen wir diese Zahl durch die Basis (in unserem Fall 2), bis wir als Ergebnis 0 erhalten. Dabei verwenden wir die ganzzahlige Division mit Rest. Und genau diese Reste werden, wie sie in Abbildung 1.1 sehen, die gesuchte Binärzahl ergeben. Abb. 1.1: Umrechnung vom Dezimalins Binärsystem am Beispiel von 110. Wir teilen zu Beginn die Zahl 110 durch 2. Das Ergebnis ist 55 mit einem Rest von 0. Diese 0 ist das niederwertigste Bit (auch least significant bit) unserer gesuchten Binärzahl. Da das Ergebnis ungleich 0 ist, teilen wir es wiederum durch 2. Diesmal ist das Ergebnis 27 mit einem Rest von 1. Diese 1 ist das zweit-niederwertigste Bit. Da 27 immer noch größer als 0 ist, teilen wir wieder durch 2. Das Ganze wiederholen wir so lange, bis das Ergebnis 0 ist. Anhand der Reste erhalten wir die gesuchte Binärzahl: 11010 = 11011102 . In diesem Beispiel haben wir durch die Zahl 2 geteilt, da wir ins Binärsystem umrechnen wollten. Analog können wir auch bspw. durch 8 teilen, um ins Oktalsystem zu konvertieren. Die Umrechnung von Zahlen können Sie mit der folgenden Kontrollaufgabe üben. K Kontrollaufgabe 1.4: Zahlenkonvertierung Konvertieren Sie die folgenden Zahlen ins Binär- und Oktalsystem: • 102310 • 59810 • 97610 1.3.3 Bits und Bytes In der Informatik treffen wir nicht nur auf den Begriff Bit, sondern auch auf den Begriff Byte. Ein Byte sind 8 Bit. Bei der Größe von Datenträgern stoßen wir zudem auf Größen wie „100 Gigabyte“ oder „1 Terabyte“. Bei der Umrechnung in Bit ist aber Vorsicht geboten: Hier muss u. a. zwischen Binär- und Dezimalpräfix unterschieden werden. Dezimalpräfixe benutzen wir im alltäglichen Leben bspw. bei Längen- oder Gewichtsangaben. So ist ein Zentimeter ein hundertstel Meter, ein Kilometer sind 1000 Meter. Die Umrechnungszahl ist eine Zehnerpotenz, was naheliegend ist, da wir im Dezimalsystem rechnen. Bei einem Kilobyte würde es sich demzufolge um 1000 Byte handeln. Richtig? Falsch? Kommt darauf an. Da der Computer im Binärsystem rechnet, ist eine Zehnerpotenz für die Umrechnung ungünstig. Eine Zweierpotenz würde mehr Sinn machen. Bis zum Jahr 1996 1.3 Zahlensysteme Seite 17 gab es keine Einheitenvorsätze, sodass bspw. für das Dezimalpräfix „Kilo“ die Umrechnungszahl 1024 genutzt wurde. Es wurde aber ebenso gerne eine Zehnerpotenz genutzt (in diesem Fall 1000). Teilweise treten sogar Mischformen auf, wie bspw. bei der Größe einer 3,5-Zoll-Diskette (siehe Exkurs 1.1). Wenn man also die Größenangabe „10 Kilobyte“ hört, kann man nicht genau wissen, ob es sich 10 · 1024 Byte oder nur um 10 · 1000 Byte handelt. Aus diesem Grund schlug die IEC neue Einheitenvorsätze vor, die Binärpräfixe verwenden. Für die Binärpräfixe nehmen wir das Dezimalpräfix, entfernen die zweite Silbe, und setzen stattdessen „bi“ ein. Aus „Kilo“ wird „Kibi“, aus „Mega“ „Mebi“, aus „Tera“ „Tebi“ usw. Bei den Binärpräfixen ist die Umrechnungszahl stets eine Zweierpotenz, sodass keine Unklarheiten entstehen können. Aus Tabelle 1.2 können Sie noch einmal gesondert Präfixe und Umrechnungszahlen entnehmen. Dezimalpräfix Kürzel Umrechung Binärprefix Kürzel Umrechnung Kilo kB oder KB 1kB = 103 Bytes oder 210 Bytes Kibi KiB 1KiB = 210 Bytes Mega MB 1MB = 106 Bytes oder 220 Bytes Mebi MiB 1MiB = 220 Bytes Giga GB 1GB = 109 Bytes oder 230 Bytes Gibi GiB 1GiB = 230 Bytes Tera TB 1TB = 1012 Bytes oder 240 Bytes Tebi TiB 1TiB = 240 Bytes Exkurs 1.1: 3,5-Zoll-Disketten Die Größe von 3,5-Zoll-Disketten wurde mit 1,4 MB angegeben. Wieviel Speicherplatz war also auf solch einer Diskette vorhanden? Zwei Lösungen würden Sinn machen: 1. 1, 4 · 1000 · 1000 = 1.400.000 Byte 2. 1, 4 · 1024 · 1024 = 1.468.006 Byte Tatsächlich ist keine der beiden Antworten richtig. Bei der Umrechnung von Mega- in Kilobyte wird die Zahl 1000 genutzt, bei der Umrechnung von Kiloin Byte die Zahl 1024. Es standen also 1, 4 · 1000 · 1024 = 1.433.600 Byte Speicherplatz zur Verfügung. Tabelle 1.2: Binär- und Dezimalpräfixe im Vergleich. Die Kürzel beziehen sich auf die ByteSchreibweise. E Seite 18 Studienbrief 1 Eine Einführung in Programmiersprachen Exkurs 1.2: Einheitliches Format E Man könnte meinen, durch die Einführung der Binärpräfixe wüsste man ganz genau, wie viel Speicherplatz ein Medium hat. Leider ist das nicht der Fall, da so gut wie jeder weiterhin auf Dezimalpräfixe zurückgreift. Hinzu kommt, dass bspw. Festplattenhersteller gerne eine Zehnerpotenz als Umrechnungszahl verwenden. Wenn Sie also eine 1-TB-Festplatte kaufen, müssen Sie sich in Zukunft nicht wundern, wenn ihr Betriebssystem nur eine Festplattenkapazität von rund 0.9 TB erkennt. Das Betriebssystem rechnet in Zweierpotenzen (benutzt aber zur Anzeige dennoch Dezimalpräfixe . . . ). K K Kontrollaufgabe 1.5: Downloadgeschwindigkeit Ihr Internetprovider bietet Ihnen „DSL 16.000“ an. Finden Sie heraus, was das bedeutet und wie die Provider gewöhnlich umrechnen. Geben Sie im Anschluss die maximale Downloadgeschwindigkeit in MiB/s an. Kontrollaufgabe 1.6: Speicherplatz einer DVD Auf eine DVD passen 4, 7 GB. Recherchieren Sie, ob die Hersteller mit Zweieroder Zehnerpotenzen rechnen. Falls sie Zehnerpotenzen nutzen: Wie viel GiB stehen tatsächlich zur Verfügung? Wie hoch ist der prozentuale Unterschied? 1.3.4 Hexadezimalsystem Neben dem Binärsystem spielt in der Informatik das Hexadezimalsystem (System zur Basis 16) eine große Rolle. Zahlen im Hexadezimalsystem kann man mit einem 0x vor der Zahl kennzeichnen. Wenn die Zahl 0x9 im Hexadezimalsystem um eins erhöht wird, ist das Ergebnis 0xa oder auch 0xA. Dies entspricht dem dezimalen Wert 10. Bei weiterer Addition werden die Buchstaben gemäß Alphabet fortgesetzt. Nach der Zahl 0xf kommt es zum gewohnten Übertrag. Tabelle 1.3: Hexadezimalzahlen und ihre Entsprechung im Dezimalsystem. Dezimal 9 10 11 12 13 14 15 16 Hexadezimal 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 Alle Rechenregeln, die wir kennengelernt haben (sprich das Umrechnen vom Dezimal- ins Binärsystem und umgekehrt), gelten auch im Hexadezimalsystem. Der Grund dafür, dass das Hexadezimalsystem in der Informatik eine große Rolle spielt, ist folgender: 4 Bit lassen sich zu einer einstelligen Hexadezimalzahl zusammenfassen, zwei Hexadezimalziffern ergeben ein Byte. Dadurch lässt sich viel Schreibarbeit ersparen, Zahlen können kompakter dargestellt werden. Zudem 1.3 Zahlensysteme Seite 19 können Binärzahlen in Viererblöcke unterteilt und einzeln in Hexadezimalzahlen umgewandelt werden, wodurch sich Zahlen deutlich schneller umrechnen lassen. Beispiel 1.1: Hexadezimalzahlen B 01102 → 0x06 1111 11112 → 0x f f 0101 0101 1010 1010 → 0x55aa 1.3.5 Operatoren Die Grundrechenarten (Addition, Subtraktion, Multiplikation, Division) können auch im Dualsystem benutzt werden. Wir beschränken uns in diesem Modul auf die Addition und Subtraktion, die im Folgenden erläutert werden. Addition Bei der Addition zweier Binärzahlen gehen wir genau so vor, wie wir auch im Dezimalsystem vorgehen würden. Wir beginnen beim least significant bit. Wenn wir zwei Einsen addieren, kommt es zu einem Übertrag auf die nächsthöhere Binärstelle. Das Ergebnis von 12 + 12 ist also 02 mit einem Übertrag von 12 . In Gleichung 1.1 ist eine Beispielrechnung gezeigt, in der die Zahlen 101 11102 und 10112 addiert werden. + 1011110 1011 1101001 (1.1) An der dritten Stelle haben wir sowohl die Addition von 12 und 12 als auch einen Übertrag von der vorherigen Stelle. Das Ergebis ist 12 mit einem Übertrag von 12 . Ansonsten gibt es bei dieser Additionsaufgabe nichts zu beachten. Kontrollaufgabe 1.7: Addition Lösen Sie die folgenden Aufgaben im Binärsystem. Rechnen Sie im Anschluss die Zahlen ins Dezimalsystem um und prüfen Sie Ihre Ergebnisse. • 10102 + 11112 • 1010 10102 + 1010 10102 • 11 00112 + 11002 • 1 11112 + 12 Subtraktion Die Subtraktion zweier Binärzahlen ist ebenso simpel wie die Addition, da sie genauso funktioniert wie im Dezimalsystem. Es wird wieder beim least significant bit begonnen. Die untere/hintere Zahl (der Subtrahend) wird vom Minuenden abgezogen. Sollte das Ergebnis negativ sein (wenn wir bspw. 02 − 12 rechnen), entsteht ein Übertrag. Dieser wird an der nächsten Binärstelle zusätzlich vom Minuenden abgezogen. Zur Verdeutlichung ist in Gleichung 1.2 ein Beispiel gezeigt. K Seite 20 Studienbrief 1 Eine Einführung in Programmiersprachen − 1011110 1011 1010011 (1.2) Wenn wir rechts beginnen, rechnen wir zunächst 02 − 12 . Das Ergebnis ist −1. Wir schreiben also in diese Stelle eine 1 und nehmen, da das Ergebnis negativ ist, einen Übertrag mit zur nächsten Binärstelle. Hier rechnen wir zunächst 12 − 12 , Das Ergebnis ist 02 . Da wir aber noch den Übertrag haben, müssen wir von diesem Ergebnis wiederum 12 abziehen. Das Ergebnis ist −1, was bedeutet, dass wir auch an diese Stelle eine 12 schreiben und einen Übertrag mitnehmen. Der Rest der Aufgabe wird analog gelöst. K Kontrollaufgabe 1.8: Subtraktion Lösen Sie die folgenden Aufgaben im Binärsystem. Rechnen Sie im Anschluss die Zahlen ins Dezimalsystem um und prüfen Sie Ihre Ergebnisse. • 11112 − 11012 • 101010112 − 101010102 • 1100112 − 0011002 • 111112 − 101012 Shifting Wir haben zwar geschrieben, dass wir nur auf die Addition und Subtraktion eingehen, aber wir wollen an dieser Stelle trotzdem auf eine Besonderheit hinweisen, die uns zu einer weiteren binären Operation führt. Im Dezimalsystem fällt uns die Multiplikation und Division mit Zehnerpotenzen besonders leicht. Wir wissen, dass, wenn wir eine ganze Zahl mit 10 multiplizieren, wir nur eine Null hinten an die Zahl anfügen müssen. Analog verschieben wir bei der Division durch 10 das Komma um eine Stelle nach links. Dieser Verhalten tritt in jedem Zahlensystem auf, wenn wir mit einer Potenz der Basis multiplizieren oder dividieren. Im Binärsystem bedeutet das: Wenn wir eine Zahl mit bspw. 2 = 21 multiplizieren, so müssen wir an die Binärzahl nur eine 0 anfügen, um das Ergebnis zu erhalten. Wenn wir sie mit 4 = 22 multiplizieren, werden zwei Nullen angefügt. Wenn wir durch 2 dividieren, schneiden wir einfach das least significant bit ab. (Dies gilt nur für die ganzzahlige Division) Der Shift- oder auch Verschiebeoperator arbeitet auf ähnliche Weise. Mit diesem Operator können wir angeben, um wie viel Stellen eine Binärzahl nach links oder rechts verschoben werden soll. Der Shiftoperator wird mit << (Verschiebung nach links) bzw. >> (Verschiebung nach rechts) ausgedrückt. Hinter dem Operator steht die Anzahl der Stellen, um die verschoben wird. Sie müssen beachten, dass die Anzahl der Stellen beim Verschieben oftmals gleich bleibt. In der Informatik werden für Zahlen eine bestimmte Anzahl an Bits reserviert, bspw. 32 Bit. Diese Bitzahl ist fest. Wir können also Zahlen links und rechts „herausschieben“. Ob beim Verschieben mit Nullen oder Einsen aufgefüllt wird, 1.3 Zahlensysteme Seite 21 hängt von der Programmiersprache und der Tatsache ab, ob die Zahl positiv oder negativ ist (mehr dazu später). Im Beispiel 1.2 füllen wir bspw. mit Nullen auf. Beispiel 1.2: Bitshifting Wir wollen die Zahl 110 10102 (7 Bit fest) um zwei Stellen nach links verschieben. Dies wird folgendermaßen ausgedrückt: B 110 10102 << 2 Das Ergebnis ist: 010 10002 . Die beiden höchstwertigsten Bits wurden links herausgeschoben, dafür wurden rechts zwei Nullen hineingeschoben. Kontrollaufgabe 1.9: Bitshifting Lösen Sie die folgenden Aufgaben. Die Bitzahl ist fest. Füllen Sie mit Nullen auf. • 10 10112 >> 4 • 00 11002 >> 2 • 11 11112 << 6 • (11 00112 << 2) >> 2 Bitweise Verknüpfungen Neben dem Bitshifting gibt es binäre Verknüpfungen, die bitweise auf zwei Operanden angewendet werden. Es gibt die AND-, die OR sowie die XOR-Verknüpfung. Bei der AND-Verknüpfung müssen beide Operanden gleich 1 sein, damit das Ergebnis ebenfalls 1 ist. Ansonsten ist das Ergebnis dieser Verknüpfung 0. In Gleichung 1.3 ist ein Beispiel zu sehen. Beachten Sie, dass der Operator bitweise angewendet wird. Dies bedeutet, dass das niederwertigste Bit der ersten Zahl mit dem niederwertigsten Bit der zweiten Zahl verundet wird, das nächsthöhere der ersten Zahl mit dem nächsthöheren der zweiten Zahl usw. Anstelle des Wortes AND wird in Programmiersprachen häufig das Et-Zeichen (&) genutzt. AND 11011 01001 01001 (1.3) Bei der OR-Verknüpfung ist das Ergebnis gleich 1, wenn der eine, der andere oder beide Operanden gleich 1 sind. Im Umkehrschluss bedeutet dies, dass das Ergebnis der OR-Verknüpfung nur 0 sein kann, wenn beide Operanden gleich 0 sind. In Gleichung 1.4 sehen Sie ein Beispiel. Anstelle des Wortes OR wird in Programmiersprachen häufig ein einzelner senkrechter Strich (|) genutzt. K Seite 22 Studienbrief 1 Eine Einführung in Programmiersprachen OR 11011 01001 11011 (1.4) Die XOR-Verknüpfung entspricht dem, was wir im normalen Sprachgebrauch als „oder“ benutzen: „Das eine oder das andere, aber nicht beides“. Demzufolge ist das Ergebnis von XOR (es steht nebenbei bemerkt für „eXclusive OR“) gleich 1, wenn genau ein Operand gleich 1 ist. Ansonsten ist das Ergebnis 0, wie in Gleichung 1.5 zu sehen ist. Anstelle des Wortes XOR wird in Programmiersprachen häufig ein Zirkumflex (ˆ) benutzt. 11011 XOR 01001 10010 (1.5) In Tabelle 1.4 sehen sie die drei vorgestellen Operatoren noch einmal zusammengefasst. Tabelle 1.4: Binäre Verknüpfungen AND OR XOR 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 1 1 1 0 Der NOT-Operator Der letzte Operator, dem wir uns zuwenden, ist der NOT-Operator. Dieser wird, im Gegensatz zu den vorher genannten, nur auf eine Zahl angewendet. Er negiert bitweise, d. h. er macht auf einer 1 eine 0 und aus einer 0 eine 1. In Gleichung 1.6 sehen Sie ein Beispiel. In Programmiersprachen wir für das binäre NOT oftmals auch eine Tilde (~) benutzt. Mathematisch können wir das NOT mit einem Strich über der Zahl oder dem Symbol ¬ darstellen. NOT K 01001 10110 (1.6) Kontrollaufgabe 1.10: Binäre Operatoren Lösen Sie die folgende Aufgaben. Achten Sie auf das Zahlensystem. Verändern sie nicht die Anzahl der Bits. • 11002 & 00112 • (111100002 >> 4) XOR 111111112 • 10012 | 01102 • NOT (710 ) • 101100002 XOR 16410 • (101100002 OR 23210 ) XOR 0x f 0 1.3 Zahlensysteme Seite 23 Kontrollaufgabe 1.11: Kombination von Operatoren K Kombinieren Sie die bekannten binären Operatoren so, dass folgende Ergebnisse herauskommen: Zahl x 0 0 1 1 Zahl y 0 1 0 1 bsp) 1 0 0 0 a) 1 0 0 1 b) 1 1 1 0 c) 0 0 1 0 bsp) Das Beispiel ist die negierte OR-Verknüpfung. Die Lösung ist also: NOT ( x OR y) 1.3.6 Negative Zahlen Bisher haben wir uns nur mit positiven ganzen Zahlen beschäftigt, die wir in verschiedene Zahlensysteme konvertiert und auf denen wir Operationen ausgeführt haben. Aber es ist natürlich auch möglich, negative und gebrochene Zahlen darzustellen. Dafür gibt es mehrere Möglichkeiten, die wir Ihnen im Folgenden aufzeigen werden. Vorzeichen-Betrags-Darstellung Angenommen, wir haben für eine Zahl 8 Bit zur Verfügung. Das heißt, wir können die Zahlen von 0 bis einschließlich 511 darstellen. Wir könnten nun sagen, dass das höchstwertigste Bit angibt, ob es eine positive (0) oder negative(1) Zahl ist. Die anderen sieben Bit geben also den Wert der Zahl, das vorderste Bit das Vorzeichen an. Die Zahl −1 würde man nach dieser Methode folgendermaßen darstellen: 100000012 . Dies nennt man Vorzeichen-Betrags-Darstellung. Diese Methode hat aber einige Nachteile: Die Null hat zwei verschiedene Darstellungsarten (10000002 und 000000002 ), was die maximale Anzahl an darstellbaren Zahlen um eins reduziert. Zudem schlägt die Addition fehl, wenn wir negative Zahlen auf diese Weise darstellen, wie Gleichung 1.7 zeigt. 1010 (−2) + 0011 (3) 1101 (−5) (1.7) Es muss also eine andere Lösung gefunden werden, um negative Zahlen darzustellen. Einerkomplement Bei der Einerkomplement-Darstellung wird ebenfalls das höchstwertigste Bit als Vorzeichenbit genutzt. Um den absoluten Wert der Zahl zu bekommen, muss, sofern die Zahl negativ ist, die ganze Zahl mit dem NOT-Operator invertiert werden. Die Zahl 10012 bspw. ist eine negative Zahl (wegen der führenden Eins). Um den Wert zu erhalten, invertieren wir sie und erhalten 01102 , was dem Dezimalwert 6 entspricht. Die Zahl 10012 steht also für den Wert −6. Seite 24 Studienbrief 1 Eine Einführung in Programmiersprachen Bei der Einerkomplement-Darstellung haben wir wiederum das Problem, dass es zwei verschiedene Darstellungen der Null gibt. Dafür funktioniert die Addition ohne zusätzlichen Aufwand, sofern die Null nicht durchschritten wird. Gleichung 1.8 zeigt dafür ein Beispiel. 1010 (−5) + 0011 (3) 1101 (−2) (1.8) Wenn jedoch bei der Addition die Null durchschritten wird, stimmt das Ergebnis zunächst nicht, wie Gleichung 1.9 zeigt. 1110 (−1) + 0011 (3) (1)0001 (1) (1.9) Die führende Eins in der Gleichung ist eingeklammert, da es sich um den letzten Übertrag handelt. Da wir nur mit 4 Bit gerechnet haben, würde dieser Übertrag nicht mehr berücksichtigt werden und verfallen. Aber genau dieser Übertrag ist es, den wir auf das Ergebnis aufaddieren müssen, um das korrekte Ergebnis zu erhalten! Wir addieren also auf das bisherige Ergebnis 1 den Übertrag auf und erhalten so das korrekte Ergebnis: 2. Dies gilt für alle Additionen, bei denen die Null durchschritten wird. Da es relativ umständlich und aufwendig ist, das Einerkomplement zu nutzen, wird es kaum verwendet. Stattdessen verwenden die meisten Computer das Zweierkomplement zur internen Darstellung von negativen Zahlen. Zweierkomplement Bei der Zweierkomplement-Darstellung wird wiederum das höchstwertigste Bit der Zahl dazu genutzt, um das Vorzeichen zu bestimmen. Positive Zahlen haben als führendes Bit die 0, negative Zahlen die 1. Positive Zahlen können wie gewohnt dargestellt werden, d. h. die Zahl 01002 entspricht der Dezimalzahl 4. Zur Darstellung von negativen Zahlen wird folgendermaßen vorgegangen: 1. Stellen Sie die Zahl zunächst als positive binäre Zahl dar; z. B. 310 = 00112 2. Negieren Sie diese Zahl: NOT (00112 ) = 11002 3. Addieren Sie zu dieser Zahl eins dazu: 11002 + 12 = 11012 Analog kann man, um aus der Binärdarstellung einer negativen Zahl wieder die Dezimaldarstellung zu gewinnen, eins abziehen und dann invertieren. Heraus kommt der absolute Wert der negativen Zahl. Der Vorteil der Zweierkomplementdarstellung ist einerseits, dass es nur eine Darstellung der Zahl 0 gibt. Andererseits funktioniert die Addition ohne Einschränkung, wie in Gleichung 1.10 zu sehen ist. 1111 (−1) + 0011 (3) (1)0010 (2) (1.10) 1.3 Zahlensysteme Seite 25 Der letzte Übertrag verfällt wieder, da wir nur 4 Bit für die Zahlen zur Verfügung haben. Sollten wir zwei Zahlen addieren oder subtrahieren wollen, die unterschiedlich viele Binärstellen haben, so müssen wir eine der beiden Zahlen von links mit dem Vorzeichenbit auffüllen. Am Wert der Zahl ändert dies nichts. Zahlen werden mit dem Vorzeichenbit aufgefüllt. In Tabelle 1.5 sind noch einmal die drei verschiedenen Darstellungsweisen gegenübergestellt. Hauptsächlich wird die Zweierkomplement-Darstellung genutzt. Bits Vorzeichen-Betrag Einerkompl. Zweierkompl. 000 0 0 0 001 1 1 1 010 2 2 2 011 3 3 3 100 −0 −3 −4 101 −1 −2 −3 110 −2 −1 −2 111 −3 −0 −1 Tabelle 1.5: Darstellung negativer Zahlen im Dualsystem. 1.3.7 Darstellung gebrochener Zahlen Bei der Darstellung gebrochener Zahlen müssen wir zwei verschiedene Arten von Darstellungen berücksichtigen: Die Gleitkomma- und Festkommadarstellung. Festkommadarstellung Bei der Festkommadarstellung wird von vornherein festgelegt, dass eine bestimmte Anzahl an Bits für die Zahl nach dem Komma und eine bestimmte Anzahl an Bits für die Zahl vor dem Komma zur Verfügung steht. Bei einer 8-Bit-Zahl könnten wir festlegen: die ersten 4 Bit stehen für die Zahl vor dem Komma, die letzten 4 Bit für die Zahl nach dem Komma zur Verfügung. Wie aber wird die Zahl nach dem Komma berechnet? Hierzu sehen wir uns Abbildung 1.2 an. Abb. 1.2: Umwandlung in die binäre Festkommadarstellung In der Abbildung wurde die Zahl 6,625 in eine 8-Bit-Festkommazahl umgewandelt, wobei 4 Bits für die Nachkommastelle vorgesehen sind. Der linke Teil der Abbildung, der die Umwandlung des ganzzahligen Anteils beschreibt, ist Ihnen bereits bekannt. Um die Bitfolge für die Nachkommazahl zu errechnen, wird der Nachkommateil mit 2 multipliziert. Sollte das Ergebnis größer oder gleich 1 sein, Seite 26 Studienbrief 1 Eine Einführung in Programmiersprachen kommt an die betreffende Binärstelle eine 1 (beginnend mit der ersten Stelle nach dem Komma). Wenn das Ergebnis kleiner als 1 ist, kommt eine 0 an die Stelle. Sofern das Ergebnis nicht gleich 1, 0 war, wird der Nachkommateil erneut mit 2 multipliziert. Dies wird so lange wiederholt, bis das Ergebnis gleich 1 ist oder wir keine weiteren Bits zur Darstellung zur Verfügung haben. Genau wie bei ganzen Zahlen entsprechen gesetzte Bits einem bestimmten Zahlenwert, wie sie in Abbildung 1.3 sehen können. Indem die gesetzten Zahlenwerte aufaddiert werden, kann aus einer Binärzahl wieder eine Dezimalzahl errechnet werden. Abb. 1.3: Zuordnung von Nachkommabit zu Wert. Diese Festkommadarstellung bringt einige Probleme mit sich. Zunächst einmal kann es passieren, dass wir nicht genügend Bit zur Verfügung haben, um die Nachkommazahl darzustellen. Wenn wir bspw. 4 Bit für die Nachkommastellen 1 zur Verfügung haben, ist die kleinste darstellbare Zahl 2−4 = 16 = 0.0625. Diese Zahl ist zudem die maximale Abweichung, die entstehen kann, wenn wir eine Zahl umwandeln. Ein Komma an einer festen Position führt darüber hinaus dazu, dass Bits oft ungenutzt bleiben. Nehmen wir als Beispiel die Zahl 25, 5. Wir gehen wieder von einer 8-Bit-Zahl aus, wobei 4 Bit für den Nachkommabereich gedacht sind. Dadurch ist es uns nicht möglich, die Zahl 25 darzustellen, da 4 Bit dafür nicht ausreichen. Gleichzeitig würden wir aber für die Darstellung der 0, 5 nur 1 Bit benötigen, haben aber 4 reserviert. Kurz gesagt: Die pure Anzahl an Bits würde theoretisch ausreichen, aber durch das Komma an einer festen Position verschenken wir ggf. Speicherplatz. Die oben beschriebenen Probleme lassen sich durch eine Gleitkommadarstellung lösen. Dazu schauen wir uns (nach einer Kontrollaufgabe) den IEEE-754-Standard zur Darstellung von Gleitkommazahlen genauer an. K Kontrollaufgabe 1.12: Festkommadarstellung Stellen Sie die folgenden Zahlen in einer 16-Bit-Festkommadarstellung dar. Benutzen Sie 8 Bit für den Nachkommaanteil. Sollten Sie die Zahl nicht exakt darstellen können, berechnen Sie den absoluten Unterschied. • 84, 55 • 255, 97 • 8, 015625 Der IEEE-754-Standard Im Dezimalsystem lassen sich Zahlen, neben der normalen Schreibweise, in der Exponent-Mantissen-Schreibweise darstellen. Für die Zahl 305,47 bedeutet dies bspw. Folgendes: Exponent 305, 47 = 3, 0547 ·|{z} 10 | {z } Mantisse Basis z}|{ 2 1.3 Zahlensysteme Seite 27 Die Mantisse hat stets nur eine Stelle vor dem Komma. Die Anzahl der Stellen, um die das Komma verschoben werden muss, wird mit dem Exponenten angegeben. Ein Exponent von 2 bedeutet eine Verschiebung um zwei Stellen nach rechts. Im Dualsystem kann diese Schreibweise ebenfalls verwendet werden. Der Exponent wird so gewählt, dass immer eine 1 vor dem Komma steht. Wenn wir also die Zahl 010110, 012 in der Exponent-Mantissen-Schreibweise darstellen wollen, kommt Folgendes dabei heraus: 010110, 01 = 1, 011001 · 24 Indem wir eine Zahl im Dualsystem auf diese Weise darstellen, legen wir nicht fest, an welcher Stelle sich das Komma befindet. Man spricht auch von einer Gleitkommadarstellung. Wenn wir eine hohe Zahl vor dem Komma haben, ist der Exponent entsprechend hoch, bei vielen Stellen nach dem Komma entsprechend niedrig. Außerdem machen wir uns den Umstand zu nutze, dass immer eine 1 vor dem Komma steht. Dieses hidden bit wird bei der Darstellung der Zahl weggelassen. Dadurch verdoppelt sich der darstellbare Zahlenbereich oder die Präzision. Exponent 010110, 01 = 1 , 011001 |{z} | {z } ·2 z}|{ 4 hidden bit Mantisse Der IEEE-754-Standard gibt verschiedene Bitzahlen zur Darstellung einer Zahl vor. Wir werden uns in diesem Modul nur mit der single precision-Darstellung beschäftigen. Hier werden für eine Zahl 32 Bit benutzt, die folgendermaßen aufgeteilt sind: • 1 Bit Vorzeichen • 8 Bit Exponent • 23 Bit Mantisse Die Mantisse sowie das Vorzeichen können direkt genutzt werden. Das hidden bit wird, wie bereits erwähnt, weggelassen. Beachten Sie ebenfalls, dass für negative Zahlen kein Einer- oder Zweierkomplement angewandt wird - es wird die Vorzeichen-Betrags-Darstellung genutzt. Der Exponent wird nicht direkt genutzt, sondern auf einen so genannten Bias aufaddiert. Im Anschluss wird die Summe eingetragen. Dadurch wird bei einem negativen Exponenten die Darstellung des Vorzeichens vermieden. Der Bias berechnet sich folgendermaßen: Bias = 2#Bits für Exponent−1 − 1 In unserem Fall haben wir 8 Bit für den Exponenten. Der Bias beträgt also 127. Dieser Bias wird nun auf den Exponenten (im oberen Beispiel 4) aufaddiert. Die Summe tragen wir in unsere binäre Zahl ein und erhalten so die Gleitkommadarstellung nach IEEE 754: 010110, 01 = 1, 011001 · 24 = 0 |{z} 01000011 | {z } 0110010 | {z · · · 0} Vorzeichen Exponent + Bias Mantisse Wir haben nun also am Beispiel der Zahl 010110, 012 = 22, 2510 gezeigt, wie eine Zahl in die IEEE-754-Darstellung für Gleitkommazahlen überführt wird. Um die Seite 28 Studienbrief 1 Eine Einführung in Programmiersprachen einzelnen Schritte gebündelt noch einmal zusammenzufassen, hier das Vorgehen, um eine Dezimalzahl umzuwandeln: 1. Die Dezimalzahl in die entsprechende Binärzahl umwandeln. Das Vorzeichen wird an dieser Stelle ignoriert. 2. Zuerst den ganzzahligen Anteil umwandeln, dann die Nachkommastellen. Sollte der Nachkommaanteil nicht endlich sein, die verfügbaren Bits für die Mantisse beachten. 3. Den Exponenten und die Mantisse berechnen, indem das Komma der Zahl so verschoben wird, dass vor dem Komma nur eine 1 steht 4. Bias ausrechnen und auf den Exponenten aufaddieren 5. Die Zahl folgendermaßen zusammenstellen a) Vorzeichen b) Bias + Exponent c) Mantisse ohne hidden Bit Um aus der Gleitkommadarstellung wieder die Dezimalzahl zu gewinnen, können die Schritte rückwärts ausgeführt werden. Zur Festigung des Stoffes folgen 1.3 Zahlensysteme Seite 29 nun zwei Beispiele. Im Anschluss müssen Sie selbst in einigen Kontrollaufgaben beweisen, dass Sie die Gleitkommadarstellung verstanden haben. Beispiel 1.3: Von der Dezimalzahl in die Gleitkommadarstellung Folgende Zahl soll in die Gleitkommadarstellung nach IEEE umgewandelt werden: 567, 837 Zunächst die Darstellung der Zahl 567 in Bitschreibweise (Vorzeichen beachten!): 010 0011 0111 Die Zahl benötigt 10 Bit (das Vorzeichen zählt nicht mit). Da wir 23 Bit für die Mantisse haben, haben wir noch 13+1 Bit für den Nachkommabereich (das +1 kommt durch das hidden Bit. Der Nachkommabereich ist demnach: 11 0101 1001 0001 Die komplette Zahl lässt sich nun folgendermaßen darstellen: 010 0011 0111 , 11 0101 1001 0001 Um die Exponent-Mantissen-Schreibweise zu erhalten, müssen wir das Komma um 9 Stellen nach links verschieben, wodurch wir Folgendes erhalten: 1, 00011011111010110010001 · 29 Um die Gleitkommazahl jetzt korrekt zu schreiben, müssen wir noch den Bias berechnen: Bias= 27 − 1 = 127 und im Anschluss den Bias auf den Exponenten aufaddieren: 127 + 9 = 136. Damit haben wir alle Komponenten zusammen, um die Zahl in Gleitkommadarstellung darzustellen: 0 10001000 00011011111010110010001 B Seite 30 B Studienbrief 1 Eine Einführung in Programmiersprachen Beispiel 1.4: Von der Gleitkommadarstellung in die Dezimaldarstellung Folgende IEEE-754-Zahl soll in die Dezimaldarstellung überführt werden: 1 10001010 00000110111100101000100 Für die Dezimaldarstellung müssen wir den Bias von der Zahl 1000 10102 = 138d abziehen. Dadurch erhalten wir den Exponenten für die ExponentMantissen-Schreibweise: Exponent = 138 − 127 = 11 Die Exponent-Mantissen-Schreibweise ist also: 1, 00000110111100101000100 · 211 Beachten Sie das hidden Bit an erster Stelle. Das Vorzeichen haben wir noch nicht beachtet. Indem wir das Komma um 11 Stellen nach rechts verschieben, erhalten wir die Zahl, die wir ins Dezimalsystem umrechnen müssen: 1000 0011 0111 ,1001 0100 0100 Das Ergebnis ist 2103, 5791015625. Wenn wir nun noch das Vorzeichenbit aus der Gleitkommazahl berücksichtigen, erhalten wir das Ergebnis: −2103, 5791015625. K Kontrollaufgabe 1.13: IEEE 754 Wandeln Sie folgende Zahlen in eine Gleitkommazahl nach IEEE 754 (32 Bit) um: a) 2745, 888 b) 2, 5668 1.3.8 Zusammenfassung Ausgangspunkt für die Erläuterungen auf den letzten Seiten war die Frage, wie wir einem Computer eine simple Aufgabe, wie bspw. „Rechne 1+1“, stellen können. Das Problem ist, dass ein Computer keine Alltagssprache versteht, sondern nur Anweisungen im Binärsystem. Auf den letzten Seiten haben wir gelernt: • Wie Zahlen aus dem Dezimalsystem ins Binärsystem (und umgekehrt) umgerechnet werden • Wie positive und negative Zahlen im Binärsystem dargestellt werden können • Wie gebrochene Zahlen dargestellt werden • Wie Operationen auf Zahlen im Dualsystem angewendet werden Zudem haben Sie fundamentales Wissen erworben, um die Programmiersprache Java besser verstehen zu können. Wenn wir also später darauf hinweisen, dass 1.4 Opcodes und Assembler bspw. in einer integer-Variablen ein ganzzahliger Wert in 32 Bit in Zweierkomplementdarstellung gespeichert wird, wissen Sie genau, was dies bedeutet. Um noch einmal auf den Ausgangspunkt dieses Studienbriefs zurückzukommen: Wir möchten einem Computer folgende Anweisung geben: „Rechne 1+1“. Wir wissen mittlerweile, wie wir Zahlen im Dualsystem darstellen. Aber wie vermittelt man einem Computer, dass wir eine Addition der beiden Zahlen wünschen? Zu diesem Zweck nutzen wir sogenannte Opcodes. 1.4 Opcodes und Assembler Ein Prozessor versteht lediglich eine begrenzte Anzahl an Befehlen. Darunter sind Befehle wie die Addition und das Speichern von Daten in Registern. Jeder dieser Befehle hat eine spezielle binäre Nummer, den sogenannten Opcode. In diesem Abschnitt erläutern wir kurz und vereinfacht, wie binäre Befehle aufgebaut sind und wie die Prozessorbefehle mit Assemblercode einfacher ausgedrückt werden können als mit binärem Code. 1.4.1 Opcodes Die Hauptarbeit eines Computers läuft im Prozessor ab. Hier werden Befehle verarbeitet, um unterschiedliche Programme (wie das Betriebssystem, einen Browser oder ein Textverarbeitungsprogramm) ausführen zu können. Jeder Prozessor hat eine Reihe von Befehlen, die er beherrscht. Dazu gehören u. a. grundlegende Befehle wie die Grundrechenarten oder das Speichern von Daten. Diese Maschinenbefehle sind mit Zahlen codiert, d. h. es gibt zu jedem Befehl eine Nummer. Diese „Nummer“ ist der sogenannte Opcode. Jeder Opcode hat eine gewisse Anzahl von Parametern, die er benötigt, um korrekt ausgeführt zu werden. Diese werden hinter den Opcode geschrieben. Betrachten wir zur Verdeutlichung ein fiktives Beispiel: Wir haben den fiktiven Prozessortypen PK87. Dieser beherrscht viele Operationen, unter anderem natürlich auch die Addition. Die Addition hat den Opcode 0xA8. Als Parameter bekommt der Opcode die zwei 8-Bit-Zahlen, die er addieren soll, sowie die Nummer eines Registers, in der er das Ergebnis speichert. Um also diesem Prozessor die Anweisung „Rechne 1+1“ zu geben, müssen wir Folgendes schreiben: A8 01 01 12 Mit diesem Befehl sagen wir: Addiere (0xA8) die Zahlen 1 (0x01) und 1 (0x01) und schreibe das Ergebnis in Register 0x12. Binär ausgedrückt müssten wir schreiben: 10101000 00000001 00000001 00010010 Diese Art der Programmierung ist natürlich unnötig kompliziert, fehleranfällig und langsam. Eine angenehmere Art, die Maschinenbefehle zu schreiben, ist das Verwenden von Assemblersprache. 1.4.2 Vereinfachung durch Assemblersprache Bei der Assemblersprache wird jedem Prozessorbefehl ein Mnemonic, also eine sprachliche Entsprechung, zugeordnet. Anstatt den Opcode 0xA8 für die Addition Seite 31 Seite 32 Studienbrief 1 Eine Einführung in Programmiersprachen zu verwenden, wird bspw. der Befehl direkt mit dem Wort add ausgedrückt. Mittels Assemblersprache können wir also schreiben: add 010112, Ein Assembler übersetzt Assemblersprache in Maschinensprache add 0x01 0x01 0x12 ... Assemblersprache ... Abb. 1.4: Umwandlung von Assemblersprache in Maschinensprache durch den Assembler. um die Zahlen 1 und 1 zu addieren. Durch das Mnemonic ist der Befehl deutlich einfacher zu interpretieren. Problematisch ist an dieser Stelle aber, dass der Prozessor mit dem Wort add nichts anfangen kann. Daher muss ein in Assemblersprache geschriebenes Programm für den Prozessor übersetzt werden. Diese Übersetzung übernimmt ein Assembler genanntes Programm. Abbildung 1.4 verdeutlicht den Vorgang noch einmal. Assembler ... Maschinensprache 1010100000000001 0000000100010010 ... Assemblersprache ist eine hardwarenahe Programmiersprache. Das bedeutet, dass die Sprache der Maschinensprache sehr nahe steht. Die Befehle werden meist 1 zu 1 umgesetzt, d. h. ein Befehl in der Assemblersprache entspricht einem Opcode bzw. Prozessorbefehl. Dem gegenüber stehen die sogenannten höheren Programmiersprachen, die deutlich abstraktere und mächtigere Befehle zur Verfügung stellen. Bei einer höheren Programmiersprache entspricht ein Befehl mehreren, teilweise Hunderten Maschinenbefehlen. 1.5 Höhere Programmiersprachen Im Gegensatz zur Assemblersprache sind höhere Programmiersprachen deutlich abstrakter und losgelöster von den eigentlichen Maschinenbefehlen. Programmiersprachen (zu denen auch die Assemblersprache zählt) versuchen häufig, näher an der menschlichen Sprache zu sein, um Anweisungen verständlicher formulieren zu können. Wo bei Assembler aber hauptsächlich die Opcodes des Prozessors als einzelnes Wort codiert wurden, gehen höhere Programmiersprachen deutlich weiter. Darüber hinaus kann eine Anweisung in einer höheren Programmiersprache teilweise Hunderten oder Tausenden Zeilen Assemblercode entsprechen. Um zu verdeutlichen, welchen Komfort gerade höhere Programmiersprachen bieten, betrachten wir das wohl am häufigsten geschriebene Programm der Welt: Hello World. Dies ist die Standardaufgabe jedes Programmierkurses, in der es darum 1.5 Höhere Programmiersprachen Seite 33 geht, den Text „Hello World“ auszugeben. In der Assemblersprache MASM sieht so ein Programm folgendermaßen aus1 : Quelltext 1.1: Hello Word in Assembler 1 2 3 4 Q DATA SEGMENT Meldung db "Hello World" db "$" DATA ENDS 5 6 7 8 9 10 11 CODE SEGMENT ASSUME CS:CODE,DS:DATA Anfang: mov ax, DATA mov ds, ax mov dx, offset Meldung 12 13 14 15 16 17 18 mov ah, 09h int 21h mov ax, 4C00h int 21h CODE ENDS END Anfang Sie müssen den Code weder verstehen noch nachvollziehen können – es reicht, wenn Sie feststellen, das er kompliziert ist. Betrachten Sie dagegen folgenden JavaCode: Quelltext 1.2: Hello World in Java 1 2 3 4 Q public static void main(String[] args) { System.out.println("Hello World"); } Dieser Code ist deutlich kürzer und einfacher zu verstehen. Es geht aber noch einfacher, wie bspw. die Sprache Python zeigt: Quelltext 1.3: Hello World in Python 1 print("Hello World") Sie sehen also: Höhere Programmiersprachen können das Programmieren sehr vereinfachen. Es gibt aber immer noch ein Problem: Der Computer versteht diese Sprachen nicht. Wie Sie am Anfang dieses Studienbriefs erfahren haben, versteht ein Computer nur 0en und 1en. Hier kommt der sogenannte Compiler ins Spiel. 1 übernommen 12.08.2014 von Wikipedia: http://de.wikipedia.org/wiki/Assemblersprache, abgerufen am Q Seite 34 Studienbrief 1 Eine Einführung in Programmiersprachen 1.5.1 Compiler Ein Compiler (dt.: Übersetzer) tut genau das, was der Name vermuten lässt: Er übersetzt Programme einer Programmiersprache in eine andere. Sie haben bereits einen Compiler kennengelernt: Den Assembler. Dieser hatte Assemblersprache in Maschinensprache übersetzt, damit der Computer ein geschriebenes Programm ausführen kann. Ein Compiler übersetzt ebenso eine Programmiersprache in Maschinensprache (oder eine andere Sprache), wie Abbildung 1.5 verdeutlicht. Programmiersprache ... Abb. 1.5: Ein Compiler übersetzt eine Programmiersprache in eine andere Programmiersprache oder direkt in Maschinensprache. int i = 1 + 1; ... Compiler ... 1010100000000001 0000000100010010 ... andere Programmiersprache oder Maschinensprache Wir belassen an dieser Stelle mit dieser simplen Erklärung eines Compilers. Im Verlauf des Studiums werden Sie im Modul Compilerbau feststellen, dass doch einiges mehr dazugehört, als wir an dieser Stelle geschrieben haben. Stattdessen kommen wir nun zur Programmiersprache, mit der wir uns für den Rest dieses Moduls beschäftigen werden: Java. 1.5.2 Java Die Programmiersprache Java wurde im Auftrag von Sun Microsystems entwickelt und erschien im Jahr 1995. Der Name geht auf eine Kaffee-Bohne, der Java-Bohne, zurück. Der Kaffee dieser Bohne wurde von den Entwicklern bevorzugt getrunken, wodurch die Sprache zu ihrem Namen kam. Die Programmiersprache hat rasch Verbreitung gefunden. Im TIOBE-Index, einem Ranking der verbreitetsten Programmiersprachen (gemessen an der Anzahl der Kurse und Programmierer) belegt Java momentan Rang 2 nach der Programmiersprache C.2 Java ist zudem die Standard-Programmiersprache für Android-Apps. Da laut Google mittlerweile über 1 Milliarde Android-Geräte aktiviert wurden, haben Sie durch das Erlernen von Java eine riesige Zahl an Nutzern, die Ihre Programme nutzen könnten. Im Gegensatz zu Programmiersprachen wie C oder C++ bietet Java den Komfort, sich nicht um das Reservieren und Freigeben von Speicher kümmern zu müssen. Gleichzeitig bietet die Sprache aber auch nicht zu viele Annehmlichkeiten. Dadurch ist der „Schock“ nicht allzu groß, wenn man mit hardwarenaheren Programmiersprachen wie C konfrontiert wird. Aus diesem Grund bietet sich Java als erste Programmiersprache an. 2 Stand: August 2014 1.5 Höhere Programmiersprachen Seite 35 Die Java Virtual Machine Java muss, damit der Prozessor die geschriebenen Anweisungen verstehen kann, kompiliert werden. Im Gegensatz zu der im Abschnitt 1.5.1 Compiler beschriebenen Vorgehensweise wird Java-Code aber nicht direkt in Maschinencode kompiliert, sondern in Bytecode. Es gibt mit Maschinensprache nämlich ein Problem, das wir Ihnen bisher verschwiegen haben: Nahezu jeder Prozessortyp hat seine eigenen Maschineninstruktionen und Opcodes. Wenn Sie also ein Programm für einen bestimmten Prozessortyp kompilieren, kann das Programm höchstwahrscheinlich von einem anderen Prozessortypen nicht ausgeführt werden. Dies führt dazu, dass Programme nicht portabel sind: Sie können nicht erwarten, dass ein von Ihnen geschriebenes und kompiliertes Programm auf einem anderen Rechner läuft. Da sich Assemblersprache an den Opcodes des Prozessors orientiert, gibt es natürlich auch verschiedene Assemblersprachen. Eine davon ist MASM, von der Sie auf Seite 33 in Quelltext 1.1 bereits einen kleinen Ausschnitt gesehen haben. Java umgeht dieses Problem mit dem Bytecode. Dieser Code ist sehr ähnlich zur Assemblersprache. Er wird von der so genannten Java Virtual Machine (JVM) ausgeführt. Diese übersetzt den Code zur Laufzeit in Maschinencode und führt ihn aus. Dies hat einen gewaltigen Vorteil: Der kompilierte Java-Code funktioniert auf verschiedenen Architekturen, sofern diese über eine JVM verfügen. Abbildung 1.6 verdeutlicht noch einmal den Ablauf. ... Java int c = 1 + 1; ... Java-Compiler ... Bytecode iadd 1 1 ... JVM ... Maschinensprache 1010100000000001 0000000100010010 ... Kompilieren von Code Um Java-Code, den Sie in ganz normale Text-Dateien (mit der Endung .java) schreiben können, zu kompilieren, wird der Java programming language compiler javac genutzt. Angenommen, Sie haben ein Programm geschrieben und dieses in der Datei Programm.java gespeichert. Um diese Datei zu kompilieren, könnten Sie in einem Terminal den javac-Befehl aufrufen: javac Programm.java Abb. 1.6: Der JavaCompiler kompiliert Java-Code nicht direkt in Maschinensprache, sondern in Java Bytecode. Dieser wird in der JVM zu Maschinensprache übersetzt. Seite 36 Studienbrief 1 Eine Einführung in Programmiersprachen Sie erhalten eine Datei Programm.class. Diese enthält den Bytecode. Sie können nun mit dem Befehl java die JVM starten und den Code ausführen lassen: java Programm Dieses Kompilieren im Terminal (oder Konsole/Shell/Eingabeaufforderrung etc.) wird auch „von Hand kompilieren“ genannt. Es bedeutet, dass Sie keine Entwicklungsumgebungen benutzen, um Ihr Programm zu kompilieren, sondern den Kompiliervorgang selbst steuern. Es gibt zahlreiche solcher Entwicklungsumgebungen, auf Englisch Integrated Development Environment (IDE), von denen wir mit BlueJ auf den nächsten Seiten eine ausprobieren werden. 1.6 Objektorientierte Programmierung: Ein Beispiel Zum Ende dieses Studienbriefs wollen wir Ihnen noch eine kleine, interaktive Einführung in Java geben. Mit Hilfe dieser Einführung sollen Sie die Begriffe Klasse, Methode, Attribut, Objekt und Parameter spielerisch erlernen. Um das beschriebene Beispiel selbst analog zum Studienbrief ausführen zu können, benötigen Sie das Programm BlueJ sowie den Quellcode, den sie unter folgendem Link herunterladen können: http://www.bluej.org/objects-first/resources/projects.zip. Sie benötigen das Projekt „figures“ aus dem Ordner „chapter01“. Das Beispiel stammt aus dem Buch „Java lernen mit BlueJ“ von Barnes und Kölling. Der Rest dieses Studienbriefs orientiert sich am ersten Kapitel dieses Buches. Auch im darauf folgenden Studienbrief orientieren wir uns grob an dem Aufbau dieses Buches, werden dann aber immer mehr davon abweichen. 1.6.1 Öffnen des Projekts Laden Sie sich zunächst, wie oben beschrieben, das Programm BlueJ sowie den gepackten Projektordner projects.zip herunter. Entpacken Sie die Datei und starten Sie im Anschluss das Programm BlueJ. Nun wählen Sie links oben unter „Project“ die Option „Open Project“. Navigieren Sie nun zu dem gerade entpackten Ordner. Dort finden Sie unter projects/chapter01/ das Projekt figures. Wählen Sie dieses aus. Es erscheint nun ein Diagramm, das die verschiedenen Klassen des Programms zeigt. 1.6.2 Klassen Nachdem Sie das Projekt geladen haben, sehen Sie ein Klassendiagramm wie in Abbildung 1.7. Dies sind die verschiedenen Klassen des Projekts, die jeweils verschiende Formen repräsentieren (Circle, Square, Triangle, Person). Die Klasse Canvas repräsentiert die Leinwand, auf der die Formen später gezeichnet werden. Der gestrichelte Pfeil zu dieser Klasse bedeutet, dass die Klasse Canvas von den anderen Klassen genutzt wird. Attribute beschreiben Eigenschaften einer Klasse. Was kann man sich nun unter einer Klasse vorstellen? Eine Klasse ist so etwas wie eine allgemeine Beschreibung von Objekten. In ihr sind die Eigenschaften verzeichnet, die ein Objekt haben kann. Anhand dieser Beschreibung kann man konkrete Objekte erstellen, die für diese Eigenschaften gewisse Werte aufweisen. Wir alle wären bspw. Objekte der Klasse Mensch. Die Klasse Mensch hat Eigenschaften wie ein Alter, ein Geschlecht oder eine Haarfarbe. Hans Müller ist so gesehen ein Objekt der Klasse Mensch, mit dem Alter „26“, Geschlecht „männlich“ und Haarfarbe „blond“. Die Eigenschaften einer Klasse werden in Java als Attribute bezeichnet. 1.6 Objektorientierte Programmierung: Ein Beispiel Seite 37 Abb. 1.7: Die Klassen, die im Project „Shapes“ verwendet werden. In einer Klasse werden nur die Eigenschaften beschrieben, die für das Programm wichtig sind. Die oben genannten Eigenschaften eines Menschen sind zum Beispiel in einem Programm relevant, das Personal verwalten kann. Um auf das BlueJ-Projekt zurückzukommen: Die Klassen, die Sie sehen, beschreiben also, wie bspw. ein Kreis oder ein Quadrat aussehen. Hauptaufgabe des Programmes ist das Zeichnen dieser Formen. In der Klasse sind also Attribute gespeichert, die notwendig sind, um bspw. einen Kreis zu zeichnen. Dazu gehören u. a. eine Position und ein Durchmesser. Es existieren bisher nur Klassen, aber noch keine konkreten Kreise oder Vierecke. Dies wollen wir nun ändern. Indem wir einen Rechtsklick auf die Klasse Circle machen und die Option newCircle auswählen, erstellen wir einen neuen Kreis. Wir werden nun gefragt, wie wir die Instanz (auch Objekt genannt) nennen wollen. Wir wollen einen blauen Kreis generieren und nennen es deshalb blueCircle. Nachdem Sie auf okay geklickt haben, sehen Sie im unteren Bildschirmabschnitt das von Ihnen erstellte Objekt. Abbildung 1.8 zeigt, was Sie am Bildschirm sehen sollten. Abb. 1.8: Das Objekt blueCircle, eine Instanz der Klasse Circle. 1.6.3 Methoden Durch den Doppelpunkt beim Namen wird ausgedrückt: Das Objekt blueCircle ist eine Instanz der Klasse Circle. Unsere Absicht war, einen blauen Kreis zu erstellen. Aber es ist kein Kreis zu sehen. Der Grund ist einfach: Wir haben dem Objekt nicht gesagt, dass es sichtbar sein soll. Durch einen Rechtsklick auf das Objekt erscheint eine Liste mit Befehlen (und dem Wort void vor jedem Befehl – dazu mehr im nächsten Studienbrief). Da wir das Objekt sehen wollen, erscheint es nur logisch, dass wir makeVisible() auswählen. Und tatsächlich: Es wird ein neues Fenster geöffnet, in dem ein blauer Kreis zu sehen ist. Sie sollten nun dasselbe sehen wie in Abbildung 1.9. Was wir gerade benutzt haben, um mit dem Objekt zu interagieren und ihm eine Anweisung zu geben, wird Methode genannt. Methoden sind dazu da, die Eigenschaften eines Objektes zu verändern oder mit ihm zu interagieren. Diese Methoden werden ebenfalls in der Klasse definiert, wie wir im nächsten Studienbrief sehen werden. Die Methoden gelten für alle Instanzen einer Klasse. Das bedeutet, wenn wir einen weiteren Kreis anlegen, können wir ihn ebenfalls sichtbar machen. Methoden verändern Objekte oder lassen Objekte Dinge tun. Sie werden in der Klasse definiert. Seite 38 Studienbrief 1 Eine Einführung in Programmiersprachen Abb. 1.9: Das gezeichnete Objekt „blueCircle“. Unser nächstes Ziel ist es, einen roten Kreis zu generieren, der unter dem blauen Kreis angezeigt wird. Hierzu legen wir zunächst ein neues Kreis-Objekt an, indem wir einen Rechtsklick auf die Klasse Circle machen, newCircle auswählen und der Instanz den Namen redCircle geben. Nachdem wir dies getan haben, taucht unser neues Objekt in der unteren Leiste auf. Mit einem Rechtsklick darauf und der Auswahl von makeVisible() lassen wir den Kreis sichtbar werden. 1.6.4 Attributwerte Ein Attributwert ist ein konkreter Wert für ein Attribut. Objekte haben Attributwerte für die in der Klasse definierten Attribute. Aber etwas scheint nicht richtig funktioniert zu haben: Wir sehen lediglich den blauen Kreis, den wir vorher schon sichtbar gemacht haben. Wo ist also der rote Kreis? Um dies herauszufinden, schauen wir uns die Attributwerte des Objekts an. Hierzu machen wir einen Rechtsklick auf das Objekt redCircle und wählen „Inspect“. Wir sehen nun, wie in Abbildung 1.10 zu sehen, die Attributwerte des Objekts redCircle. Abb. 1.10: Attribute des Objekts „redCircle“. Unser roter Kreis hat demnach einen Durchmesser von 68, eine xPosition von 230, eine yPosition von 90 und die Farbe blue. Bei isVisible steht true, woraus wir schließen, dass der Kreis sichtbar ist. Ein erster Fehler wird hier schon deutlich: Unser Kreis, der eigentlich rot sein soll, ist blau. Rückblickend haben wir aber auch nirgendwo festgelegt, welche Farbe der Kreis haben soll. Wir haben den Kreis zwar redCircle genannt, aber dies ist – wie bei Menschen auch – nur ein Name. Die Standardfarbe, die für einen neuen Kreis gewählt wird, scheint blau zu sein, sodass wir für unseren ersten Kreis scheinbar Glück hatten. Warum wird uns aber nur ein blauer Kreis angezeigt, wo wir doch zwei haben sollten? Die Antwort darauf finden wir, wenn wir uns die Attributwerte des Objekts blueCircle ansehen: Sie sind identisch mit denen des redCircle-Objektes. Wenn 1.6 Objektorientierte Programmierung: Ein Beispiel Seite 39 auf einer zweidimensionalen Ebene zwei blaue Kreise mit demselben Durchmesser und der selben Position gezeigt werden, ist es nicht verwunderlich, wenn wir nur einen sehen. Um unser Vorhaben, einen roten Kreis unter den blauen zu zeichnen, zu realisieren, müssen wir die Eigenschaften des Objekts redCircle verändern. Dazu verwenden wir, wie vorher bereits erwähnt wurde, Methoden. Nach einen Rechtsklick sehen wir die verschiedenen Methoden, die uns zur Auswahl stehen. Zunächst sollte das Objekt redCircle rot gefärbt werden. Hierzu wählen wir die Methode changeColor. Bei dieser Methode sehen wir eine weitere Eigenschaft von Methoden: Ihnen können Parameterübergeben werden. Die Parameter stehen in runden Klammern hinter dem Namen der Methode. Parameter sind notwendig, damit die Methode korrekt ausgeführt werden kann. Damit bspw. eine Methode zwei Zahlen addieren kann, müssen diese Zahlen als Parameter übergeben werden. Und um, wie in unserem Beispiel, eine Farbe zu ändern, muss die Zielfarbe als Parameter übergeben werden. Bei changeColor wird String newColor als Parameter übergeben. String ist dabei der Datentyp und newColor der Name des Parameters. Der Datentyp String steht für eine Zeichenkette. Wir müssen der Methode changeColor also eine Zeichenkette übergeben. Wenn wir die Methode auswählen, werden wir aufgefordert, die Zeichenkette einzugeben. Da wir einen roten Kreis erstellen wollen, wählen wir als Zeichenkette red - und erhalten einen Fehler. Die Fehlerbeschreibung cannot find symbol - variable red hilft Ihnen wahrscheinlich nicht weiter, weshalb wir an dieser Stelle einspringen: Zeichenketten müssen in Java immer mit doppelten Anführungszeichen geschrieben werden. Das Programm erkennt also red nicht als Zeichenkette. Wenn wir "red" eintragen, erscheint keine Fehlermeldung. Zeichenketten werden in doppelten Anführungszeichen geschrieben Wenn wir nun die gezeichneten Kreise betrachten (ggf. das Fenster mit makeVisible() wieder aufrufen), sehen wir einen roten Kreis. Der blaue Kreis ist jedoch nicht mehr da. Der Grund ist einfach: Der rote Kreis wurde über den blauen gezeichnet. Als nächstes müssen wir also das redCircle-Objekt nach unten verschieben. Dazu nutzen wir die Methode moveDown(). Nach einmaliger Auswahl sehen wir beide Kreise, wobei der rote den blauen immer noch überlagert. Die Methode sollte daher noch einige Male mehr ausgeführt werden, bis der rote Kreis unter dem blauen liegt, wie in Abbildung 1.11 zu sehen ist. Abb. 1.11: Beide Objekte haben nun verschiedene Attributwerte. Zum Abschluss setzen wir uns noch zum Ziel, ein grünes Quadrat rechts von den Seite 40 Studienbrief 1 Eine Einführung in Programmiersprachen Kreisen zu zeichnen. Hierzu erstellen wir eine neue Instanz der Klasse Square und nennen sie greenSquare. K Kontrollaufgabe 1.14: Verändern von Attributwerten Verändern Sie das Objekt greenSquare mit den zur Verfügung stehenden Methoden so, sodass Sie am Ende ungefähr folgendes Bild erhalten: Hinweis: Sie müssen ggf. Methoden verwenden, die einen Parameter vom Typ int haben. Der Datentyp int steht für ganzzahlige positive und negative Werte. Mit der oberen Kontrollaufgabe beenden wir die interaktive Einführung und diesen Studienbrief. Sie sollten nun in der Lage sein, die Begriffe Klasse und Objekt voneinander zu unterscheiden. Welche Eigenschaften bzw. Attribute ein Objekt allgemein haben kann, wird in der Klasse definiert. Sie wissen, dass Methoden dazu da sind, Eigenschaften von Objekten zu verändern oder allgemein mit dem Objekt zu interagieren. Methoden können Parameter übergeben werden. Jeder Parameter hat einen Datentyp. Sie haben die Datentypen String für Zeichenketten und int für ganzzahlige Werte kennengelernt. E Exkurs 1.3: Klasse oder Objekt? Es ist bei einer Bezeichnung nicht immer klar, ob es sich um eine Bezeichnung für eine Klasse oder ein Objekt handelt. Nehmen wir als Beispiel die Bezeichnung Spinne. Die Spinne könnte sowohl ein Objekt der Klasse Tier als auch eine eigene Klasse sein, zu der wir dann konkrete Spinnen (z. B. „Tarantel“ oder „Hans“, der zahme Weberknecht aus der Tierhandlung A) generieren können. Entscheidend für die Zuordnung ist unsere Anwendung: Wollen wir Tiere wie die Spinne nur ganz allgemein abbilden, z. B. mit einer Bezeichnung und einer maximalen Größe? Dann reicht eine grobe Klasse wie Tier. Wollen wir aber die Lagerverwaltung eines Zoogeschäftes programmieren, kann es Sinn machen, mehr ins Detail zu gehen. 1.7 Zusammenfassung Computer verstehen keine menschliche Sprache. Sie verstehen lediglich eine Kombination aus 0en und 1en. Dies wird als Maschinensprache bezeichnet. Basis dafür 1.7 Zusammenfassung ist das Binärsystem. Anders als im Dezimalsystem, in dem an einer Stelle die Zahlen von 0 bis 9 stehen können, können im Binärsystem an einer Stelle nur die Zahlen 0 oder 1 stehen. Neben dem Binärsystem gibt es theoretisch noch unendlich viele weitere Zahlensysteme, von denen hauptsächlich das Oktal-, Dezimal- und Hexadezimalsystem relevant sind. Alle Zahlen eines Zahlensystems lassen sich beliebig in einem anderen Zahlensystem darstellen. Um einen Computer auf einfache Weise Anweisungen zu geben, gibt es Programmiersprachen. Diese Sprachen sind oftmals näher an der menschlichen Sprache und bieten eine Syntax, im Rahmen derer es möglich ist, dem Computer Anweisungen zu geben. Ein Compiler sorgt dafür, dass die in einer Programmiersprache verfassten Anweisungen in eine für den Computer verständliche Sprache übersetzt werden. Eine besondere Art von Compiler ist der Assembler. Dieser übersetzt Assemblersprache in Maschinensprache. Assemblersprache selbst bietet Mnemonics, welche den Opcodes eines Prozessors entsprechen. Die Programmiersprache Java ist eine objektorientierte Programmiersprache, mit der wir uns im Rahmen dieses Moduls beschäftigen werden. Java-Code wird nicht direkt in Maschinencode übersetzt, sondern in eine Zwischensprache, den sogenannten Bytecode. Dieser Bytecode wird von der Java Virtual Machine (JVM) ausgeführt. Vorteil davon ist, dass Bytecode auf jedem Computer funktioniert, unabhängig von der Architektur. Voraussetzung ist lediglich, dass eine JVM vorhanden ist. Bei einer objektorientierten Programmiersprache werden Anweisungen mit Hilfe von Objekten formuliert. In einer Klasse werden die allgemeinen Eigenschaften von gleichartigen Objekten, auch Attribute genannt, zusammengefasst. Neben den Attributen werden in einer Klasse noch Methoden definiert. Mittels Methoden kann man Objekte verändern oder Anweisungen an Objekte geben. Falls eine Methode zusätzliche Informationen benötigt, um ausgeführt werden zu können, können diese als Parameter übergeben werden. Für die Attribute, die in einer Klasse definiert wurden, haben Objekte konkrete Attributwerte. Objekte gehören immer einer Klasse an und werden auch als Instanz dieser Klasse bezeichnet. Seite 41 Seite 42 Studienbrief 1 Eine Einführung in Programmiersprachen 1.8 Übungen 1.8.1 Erläuterungen zum Übungsablauf Dieses Modul besteht aus zwei Lehrveranstaltungen, die jeweils im 1. bzw. 2. Studiensemester angeboten werden. Am Ende des zweiten Semesters schreiben Sie eine Prüfung, die den Stoff der beiden Lehrveranstaltungen abfragt. Diese Prüfung ist 10 ECTS wert. Um zu der Prüfung zugelassen zu werden, ist es notwendig, dass Sie die Übungsaufgaben am Ende jedes Studienbriefs bearbeiten. Es gibt dabei zwei verschiedene Arten von Übungsaufgaben: Bepunktete und nicht-bepunktete Übungsaufgaben. Bei den Nicht-bepunkteten bleibt es Ihnen überlassen, ob Sie die Aufgaben erledigen. Die Lösungen zu diesen Aufgaben gibt es im Verlauf des Semesters. Die bepunkteten Aufgaben müssen Sie bearbeiten und über ein Abgabesystem, das in der ersten bepunkteten Aufgabe erläutert wird, einreichen. Sie müssen in jeder Lehrveranstaltung mindestens 70 % der Punkte erreichen, um zu der Prüfung zugelassen zu werden. Die Punkte für diese Lehrveranstaltung sind dabei folgendermaßen aufgeteilt: • SB1: 10 Punkte • SB2: 20 Punkte • SB3: 30 Punkte • SB4: 40 Punkte • SB5: 50 Punkte Es gibt also insgesamt 150 Punkte, die Sie erreichen können. Sie müssen davon mindestens 105 erreichen, um zu der Prüfung zugelassen zu werden. Es gibt aber einige Dinge, die das Bearbeiten der Aufgaben erleichtern und Sie zusätzlich motivieren sollen: • Sie haben bis kurz vor Ende des Semesters (15. März 2015) Zeit, die Lösungen einzureichen • Sie haben beliebig viele Versuche • Sie erfahren nach jeder Einreichung, wie viele Punkte Sie erreicht haben • Wenn Sie die Aufgaben früher lösen, werden Ihnen die erreichten Punkte als Bonuspunkte angerechnet • Ab einer bestimmten Zahl an Bonuspunkten erhalten Sie einen Notenbonus in der Klausur Die genauen Zeitpunkte, bis wann Übungsaufgaben abgegeben werden müssen, damit die Punkte als Bonuspunkte zählen, erfahren Sie am Anfang des Semesters. Um das System besser zu verstehen, ein Beispiel: Die Übungsaufgabe des Studienbriefs 1 soll bis zum 30. Oktober abgegeben werden, um Bonuspunkte zu erhalten. Sie reichen die Aufgabe am 29. Oktober ein und erreichen 8 Punkte. Diese Punkte wandern auf Ihr Bonuskonto. Da Sie nachträglich einen Fehler entdeckt haben, reichen Sie am 1. November eine verbesserte Version der Aufgabe ein. Diesmal erhalten Sie die vollen 10 Punkte. Da die Frist für die Aufgabe abgelaufen ist, erhalten Sie die 2 zusätzlichen Punkte nicht als 1.8 Übungen Seite 43 Bonuspunkte. Da Sie aber generell bis zum Ende des Semesters Zeit haben, die Aufgaben zu bearbeiten, zählen die zwei zusätzlichen Punkte natürlich zu Ihrem Gesamtpunktestand, der für die Zulassung zur Prüfung wichtig ist, hinzu. Sie haben also insgesamt bereits 10 Punkte erreicht, davon sind 8 Punkte Bonuspunkte. Folgende Anzahl an Bonuspunkten müssen Sie erreichen, um die entsprechende Notenverbesserung zu erhalten: • 128 Punkte: Verbesserung um 0,3 Notenpunkte • 142 Punkte: Verbesserung um 0,7 Notenpunkte • 150 Punkte: Verbesserung um 1,0 Notenpunkte Sie sehen also: Wenn Sie die Aufgaben frühzeitig bearbeiten, wirkt sich dies positiv auf Ihre Note aus. Aber selbst, wenn Sie die Aufgaben nicht rechtzeitig bearbeiten können, können Sie in der Klausur trotzdem noch eine 1,0 erreichen. In der zweiten Lehrveranstaltung dieses Moduls können Sie ebenfalls Bonuspunkte erreichen. Bei der Verbesserung des Notenschnittes wird aber der Durchschnitt aus beiden Semestern berechnet, um die tatsächliche Verbesserung zu berechnen. Angenommen, Sie haben im ersten Semester eine Verbesserung um 1,0 Notenpunkte erreicht, im zweiten Semester aber nur eine Verbesserung von 0,3. Dies ergibt insgesamt eine Verbesserung von 0,7 Notenpunkten. Falls der Durchschnittswert genau mittig zwischen zwei Notenpunkten steht, entscheidet die Verbesserung der zweiten Lehrveranstaltung, da diese schwieriger ist. Wenn Sie also im ersten Semester eine Verbesserung von 0,7 und im zweiten Semester eine Verbesserung von 0,3 haben, erhalten Sie insgesamt nur eine Verbesserung von 0,3 Notenpunkten. Die Verbesserung kann nur angerechnet werden, wenn die Klausur bestanden wird. Sie müssen also in der Klausur mindestens die Note 4.0 erreichen. Übung 1.1: Begriffe Füllen Sie das Kreuzworträtsel aus. Ü Seite 44 Studienbrief 1 Eine Einführung in Programmiersprachen Ü :DDJHUHFKW 'DWHQW\SI¾UJDQ]]DKOLJH :HUWH /¦VVW2EMHNWH'LQJHWXQ ,QLKUZHUGHQ0HWKRGHQ XQG$WWULEXWHGHILQLHUW .DQQ0HWKRGHQ ¾EHUJHEHQZHUGHQ %HLGHU'DUVWHOOXQJLVW GDV.RPPDIHVW KDUGZDUHQDKH 3URJUDPPLHUVSUDFKH ,QLKUODXIHQ -DYD3URJUDPPH (LJHQVFKDIWHLQHV 2EMHNWHV 'DWHQW\SI¾U=HLFKHQNHWWH +DQVLVWHLQGHU.ODVVH 0HQVFK (LQ=DKOHQV\VWHP 6\VWHP 9HUVFKLHEHQYRQ%LWV 6HQNUHFKW 1XPPHUQI¾U 0DVFKLQHQEHIHKOH ,(((LVWHLQH 'DUVWHOOXQJ 'DULQZLUGSURJUDPPLHUW (LQ2EMHNWLVWHLQHHLQHU .ODVVH &RPSXWHUYHUVWHKHQQXU $QZHLVXQJHQLP EHUVHW]W $VVHPEOHUVVSUDFKH EHUVHW]W 3URJUDPPLHUVSUDFKHQLQ DQGHUH :HUWHLQHU(LJHQVFKDIW HLQHV2EMHNWHV .DQQQXURGHUVHLQ :RUWHQWVSUHFKXQJHQYRQ 0DVFKLQHQEHIHKOHQ (LQH3URJUDPPLHUVSUDFKH %LW Übung 1.2: IEEE-754 Wandeln Sie folgende Zahlen in die Gleitkommadarstellung nach IEEE-754 (32 Bit) um: a) 4444,4444 b) -85,8875 c) 2209,87 1.8 Übungen Übung 1.3: Einer- und Zweierkomplement Stellen Sie folgende Zahlen im Einer- und Zweierkomplement dar: Seite 45 Ü a) -523 b) -5242 c) -127 Übung 1.4: Abgabesystem (10 Punkte) Diese Aufgabe dient dazu, das Abgabesystem, das wir in dieser Lehrveranstaltung nutzen, kennenzulernen. Viele der Schritte, die Sie in dieser Aufgabe durchführen, sind einmalig und müssen daher nicht für jede Übungsabgabe wiederholt werden. Die Aufgabe unterteilt sich grob in 4 Schritte: • Ein Schlüsselpaar zur Authentifizierung generieren • Ihren public-key auf der Webseite hochladen, um ihr Git-repository zu generieren • sich mit Git vertraut machen • Ein Hello-World-Programm in das repository und in den richtigen Ordner comitten. Die einzelnen Schritte werden in Videos behandelt, die speziell für diese Lehrveranstaltung aufgezeichnet wurden. Wenn sie analog zu den Video mitarbeiten, haben Sie die Aufgabe bereits erfüllt. Wichtig ist, dass Sie sich bei dieser und den kommenden Übungsabgaben genau an die Vorgaben halten, was Ordnerstruktur, Dateinamen, Methodennamen und die Reihenfolge von Parametern betrifft. Nur so können Ihre Aufgaben automatisiert korrigiert werden. Sofern nichts anderes gefordert ist, sollen immer nur die .java-Dateien hochgeladen werden. Falls Sie andere Dateien, wie zum Beispiel kompilierte Dateien oder Eclipse-Projekt-Dateien hochladen, erhalten Sie einen Punktabzug. Der folgende Code soll in einer Datei Hello.java gespeichert werden: 1 2 3 4 5 6 7 public class Hello { public static void main(String[] args) { System.out.println("Hello world"); } } Die Datei sollte sich in einem Order namens SB1 befinden, wenn Sie die Datei ins Repository hochladen. Die Videos gehen noch einmal gesondert auf diese Dinge ein. Ü Anhang Anhang Seite 153 Liste der Lösungen zu den Kontrollaufgaben Liste der Lösungen zu den Kontrollaufgaben Lösung zu Kontrollaufgabe 1.1 auf Seite 15 110011002 = 27 + 26 + 23 + 22 = 128 + 64 + 8 + 4 = 204 111111112 = 27 + · · · + 21 + 20 = 255 = 28 − 1 00000001 = 20 = 1 10000000 = 27 = 128 Lösung zu Kontrollaufgabe 1.2 auf Seite 15 00108 = 81 = 8 77778 = 7 · 83 + 7 · 82 + 7 · 81 + 7 · 80 = 84 − 1 = 4095 47068 = 4 · 83 + 7 · 82 + 6 · 80 = 2502 64038 = 6 · 83 + 4 · 82 + 3 · 80 = 3331 Lösung zu Kontrollaufgabe 1.4 auf Seite 16 102310 = 11 1111 1111 = 17778 59810 = 10 0101 0110 = 11268 97610 = 11 1101 0000 = 17208 Lösung zu Kontrollaufgabe 1.5 auf Seite 18 Bei den Internetprovidern entspricht DSL 16.000 meist einer Downloadrate von 16 MBit/s (Umrechnungszahl 1000 - also Zehnerpotenz). Dies entspricht 2MiB/s. Lösung zu Kontrollaufgabe 1.6 auf Seite 18 Die Hersteller geben die Kapazität dezimal an. 4, 7GB entsprechen also 4, 7 · 109 Bytes. Wenn wir diese Zahl durch 23 0 teilen, erhalten wie die tatsächliche Kapazität in GiB: 4, 377GiB. Dies entspricht einer prozentualen Abweichung von rund 7, 37 Prozent. Lösung zu Kontrollaufgabe 1.7 auf Seite 19 10102 + 11112 = 110012 1010 10102 + 1010 10102 = 1 0101 01002 11 00112 + 11002 = 11 11112 1 11112 + 12 = 10 0000 Beachten Sie, dass in der Informatik eine bestimme Anzahl an Bits für eine Zahl reserviert wird. So kann es passieren, dass bei einer Addition (oder Subtraktion) die höchstwertigsten Bits verfallen und das Ergebnis so nicht korrekt ist. Dies Seite 183 Seite 184 Liste der Lösungen zu den Kontrollaufgaben passiert, wenn bei der Addition die maximal darstellbare Zahl durchschritten wird. Wir sprechen auch von einem overflow. Lösung zu Kontrollaufgabe 1.8 auf Seite 20 11112 − 11012 = 00102 1010 10112 − 1010 10102 = 0000 00012 11 00112 − 00 11002 = 10 01112 1 11112 − 1 01012 = 0 10102 Lösung zu Kontrollaufgabe 1.9 auf Seite 21 10 10112 >> 4 = 00 00102 00 11002 >> 2 = 00 00112 11 11112 << 6 = 00 0000 (11 00112 << 2) >> 2 = 00 00112 Lösung zu Kontrollaufgabe 1.10 auf Seite 22 11002 & 00112 = 00002 (1111 00002 >> 4) XOR 1111 11112 = 1111 00002 10012 | 01102 = 11112 NOT (710 ) = NOT (1112 ) = 0002 1011 00002 XOR 16410 = 1011 00002 XOR 1010 01002 = 0001 0100 (1011 00002 OR 23210 ) XOR 0x f 0 = (1011 00002 OR 1110 10002 ) XOR 1111 00002 = 1111 10002 XOR 1111 00002 = 0000 10002 Lösung zu Kontrollaufgabe 1.12 auf Seite 26 84, 55 = 0101 0100 1000 1100 = 84, 546875 Differenz: 0,003125 255, 97 = 1111 1111 1111 1000 = 255, 96875 Differenz: 0,00125 8, 015625 = 0000 1000 0000 0100 Differenz: 0 Liste der Lösungen zu den Kontrollaufgaben Lösung zu Kontrollaufgabe 1.13 auf Seite 30 a) 2745, 888 = 0 10001010 01010111001111000110101 b) 2, 5668 = 0 1000 0000 01001000100011001110100 Seite 185 Verzeichnisse Seite 187 Verzeichnisse I. Abbildungen Abb. Abb. Abb. Abb. Abb. 1.1: 1.2: 1.3: 1.4: 1.5: Umrechnung vom Dezimal- ins Binärsystem am Beispiel von 110. . . . . . . . . . . . . . . . Umwandlung in die binäre Festkommadarstellung . . . . . . . . . . . . . . . . . . . . . . . . Zuordnung von Nachkommabit zu Wert. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Umwandlung von Assemblersprache in Maschinensprache durch den Assembler. . . . . . . Ein Compiler übersetzt eine Programmiersprache in eine andere Programmiersprache oder direkt in Maschinensprache. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 1.6: Der Java-Compiler kompiliert Java-Code nicht direkt in Maschinensprache, sondern in Java Bytecode. Dieser wird in der JVM zu Maschinensprache übersetzt. . . . . . . . . . . . . . . . Abb. 1.7: Die Klassen, die im Project „Shapes“ verwendet werden. . . . . . . . . . . . . . . . . . . . . Abb. 1.8: Das Objekt blueCircle, eine Instanz der Klasse Circle. . . . . . . . . . . . . . . . . . . . . Abb. 1.9: Das gezeichnete Objekt „blueCircle“. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 1.10: Attribute des Objekts „redCircle“. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 1.11: Beide Objekte haben nun verschiedene Attributwerte. . . . . . . . . . . . . . . . . . . . . . Abb. 2.1: Die Bestandteile einer Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 2.2: Defintion von der Klasse sowie von Attributen. . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 2.3: Die Definition von Instanzmethoden. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abb. 2.4: Eine Methode unterteilt sich in einen Methodenkopf und einen Methodenrumpf. . . . . . . . Abb. 2.5: Beide Variablen zeigen auf denselben Platz im Hauptspeicher. . . . . . . . . . . . . . . . . . Abb. 2.6: Gültigkeitsbereiche von Variablen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 25 26 32 34 35 37 37 38 38 39 47 51 56 56 69 70 II. Beispiele Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel Beispiel 1.1: 1.2: 1.3: 1.4: 2.1: 2.2: 2.3: 2.4: 2.5: 2.6: 2.7: 2.8: 2.9: 2.10: 2.11: 2.12: 2.13: 3.1: 3.2: 3.3: 3.4: Hexadezimalzahlen . . . . . . . . . . . . . . . . . . . . . . Bitshifting . . . . . . . . . . . . . . . . . . . . . . . . . . . Von der Dezimalzahl in die Gleitkommadarstellung . . . . Von der Gleitkommadarstellung in die Dezimaldarstellung Shortcuts und Funktionen in Eclipse . . . . . . . . . . . . . Mehrzeilige Kommentare . . . . . . . . . . . . . . . . . . . mixedCase . . . . . . . . . . . . . . . . . . . . . . . . . . Methodenkopf . . . . . . . . . . . . . . . . . . . . . . . . System.out.println() . . . . . . . . . . . . . . . . . . . Rückgabe mit return . . . . . . . . . . . . . . . . . . . . Babyautos . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine ausführbare Klasse . . . . . . . . . . . . . . . . . . . Konstruktor . . . . . . . . . . . . . . . . . . . . . . . . . . this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Default-Konstruktor 1 . . . . . . . . . . . . . . . . . . . . Default-Konstruktor 2 . . . . . . . . . . . . . . . . . . . . Statische Methoden 1 . . . . . . . . . . . . . . . . . . . . Sichtbarkeiten . . . . . . . . . . . . . . . . . . . . . . . . Klasse Human mit Sichtbarkeiten . . . . . . . . . . . . . . Gerade oder ungerade? . . . . . . . . . . . . . . . . . . . Zählen von 1 bis 10 mit while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 21 29 30 50 52 55 57 59 66 68 72 73 74 75 75 77 89 91 98 103 III. Definitionen Definition 1.1: Zahlensysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Definition 1.2: Wertigkeit einer Zahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 14 Seite 188 Verzeichnisse IV. Exkurse Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs Exkurs 1.1: 1.2: 1.3: 2.1: 2.2: 2.3: 3.1: 3.2: 3.3: 3.4: 4.1: D.1: D.2: 3,5-Zoll-Disketten . . . . . . . . . . . Einheitliches Format . . . . . . . . . Klasse oder Objekt? . . . . . . . . . . Modularisierung . . . . . . . . . . . . Overflow . . . . . . . . . . . . . . . . Ganzzahlige Division . . . . . . . . . Usereingaben . . . . . . . . . . . . . fill-Methode . . . . . . . . . . . . . foreach-Schleife . . . . . . . . . . . . Immutable . . . . . . . . . . . . . . . Die Klasse Object . . . . . . . . . . . Label . . . . . . . . . . . . . . . . . . Zwei verschiedene Vorgehensweisen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 18 40 51 54 62 98 105 108 112 125 171 176 Umrechnung ins Dezimalsystem . . Oktalsystem . . . . . . . . . . . . . Zweierpotenzen . . . . . . . . . . . Zahlenkonvertierung . . . . . . . . Downloadgeschwindigkeit . . . . . Speicherplatz einer DVD . . . . . . Addition . . . . . . . . . . . . . . . Subtraktion . . . . . . . . . . . . . . Bitshifting . . . . . . . . . . . . . . Binäre Operatoren . . . . . . . . . . Kombination von Operatoren . . . . Festkommadarstellung . . . . . . . IEEE 754 . . . . . . . . . . . . . . . Verändern von Attributwerten . . . IDEs . . . . . . . . . . . . . . . . . . Texteditoren . . . . . . . . . . . . . Konventionen bei Attributen . . . . Klassen . . . . . . . . . . . . . . . . Methodenköpfe . . . . . . . . . . . Anlegen von Variablen . . . . . . . . Gerade und ungerade Zahlen . . . . Variablenwert . . . . . . . . . . . . Inkrement . . . . . . . . . . . . . . Kopieren von Objekten . . . . . . . Konstruktoren . . . . . . . . . . . . String-API . . . . . . . . . . . . . . . Random . . . . . . . . . . . . . . . Wird der Code ausgeführt? . . . . . if-Statements . . . . . . . . . . . . Gerade Zahlen zwischen 0 und 1000 Zählen von 1 bis 10 mit do-while . Kopf- oder fußgesteuert? . . . . . . Wrapperklassen . . . . . . . . . . . MyTwitter . . . . . . . . . . . . . . . Die Klasse Dog . . . . . . . . . . . . Gemeinsamkeiten . . . . . . . . . . Annotations . . . . . . . . . . . . . Code reduzieren . . . . . . . . . . . Comparable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 15 15 16 18 18 19 20 21 22 23 26 30 40 49 50 55 56 58 61 63 65 65 69 76 92 92 96 99 102 104 104 112 114 124 124 128 129 135 V. Kontrollaufgaben Kontrollaufgabe 1.1: Kontrollaufgabe 1.2: Kontrollaufgabe 1.3: Kontrollaufgabe 1.4: Kontrollaufgabe 1.5: Kontrollaufgabe 1.6: Kontrollaufgabe 1.7: Kontrollaufgabe 1.8: Kontrollaufgabe 1.9: Kontrollaufgabe 1.10: Kontrollaufgabe 1.11: Kontrollaufgabe 1.12: Kontrollaufgabe 1.13: Kontrollaufgabe 1.14: Kontrollaufgabe 2.1: Kontrollaufgabe 2.2: Kontrollaufgabe 2.3: Kontrollaufgabe 2.4: Kontrollaufgabe 2.5: Kontrollaufgabe 2.6: Kontrollaufgabe 2.7: Kontrollaufgabe 2.8: Kontrollaufgabe 2.9: Kontrollaufgabe 2.10: Kontrollaufgabe 2.11: Kontrollaufgabe 3.1: Kontrollaufgabe 3.2: Kontrollaufgabe 3.3: Kontrollaufgabe 3.4: Kontrollaufgabe 3.5: Kontrollaufgabe 3.6: Kontrollaufgabe 3.7: Kontrollaufgabe 3.8: Kontrollaufgabe 3.9: Kontrollaufgabe 4.1: Kontrollaufgabe 4.2: Kontrollaufgabe 4.3: Kontrollaufgabe 4.4: Kontrollaufgabe 4.5: Tabellen Seite 189 VI. Tabellen Tabelle Tabelle Tabelle Tabelle Tabelle Tabelle Tabelle 1.1: 1.2: 1.3: 1.4: 1.5: 2.1: 3.1: Dezimalzahlen und ihre Entsprechung im Binärsystem . . . . . Binär- und Dezimalpräfixe im Vergleich. Die Kürzel beziehen sich Hexadezimalzahlen und ihre Entsprechung im Dezimalsystem. . Binäre Verknüpfungen . . . . . . . . . . . . . . . . . . . . . . . Darstellung negativer Zahlen im Dualsystem. . . . . . . . . . . Primitive Datentypen in Java . . . . . . . . . . . . . . . . . . . . Binäre Verknüpfungen . . . . . . . . . . . . . . . . . . . . . . . . . auf . . . . . . . . . . . . die . . . . . . . . . . . . . . . . . . . . . Byte-Schreibweise. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 17 18 22 25 53 96 VII. Literatur David J Barnes and Michael Kölling. Java lernen mit BlueJ. Pearson, 2013. Lasse Koskela. Test Driven: Practical TDD and Acceptance TDD for Java Developers. Manning Pubn, 2007. Guido Krüger and Thomas Stark. Handbuch der Java-Programmierung: Standard Edition Version 6. AddisonWesley, 2009. Kathy Sierra and Bert Bates. Java von Kopf bis Fuss. O Reilly, 2006.