Lernen Sie Java von Grund auf

Sie möchten also in Java programmieren? Das ist großartig und Sie sind an der richtigen Stelle. Die Java 101-Serie bietet eine selbstgeführte Einführung in die Java-Programmierung, beginnend mit den Grundlagen und mit allen Kernkonzepten, die Sie kennen müssen, um ein produktiver Java-Entwickler zu werden. Diese Serie ist technisch und enthält zahlreiche Codebeispiele, die Ihnen helfen, die Konzepte im weiteren Verlauf zu verstehen. Ich gehe davon aus, dass Sie bereits Programmiererfahrung haben, nur nicht in Java.

In diesem ersten Artikel wird die Java-Plattform vorgestellt und der Unterschied zwischen den drei Editionen Java SE, Java EE und Java ME erläutert. Außerdem erfahren Sie mehr über die Rolle der Java Virtual Machine (JVM) bei der Bereitstellung von Java-Anwendungen. Ich werde Ihnen helfen, ein Java Development Kit (JDK) auf Ihrem System einzurichten, damit Sie Java-Programme entwickeln und ausführen können, und ich werde Ihnen den Einstieg in die Architektur einer typischen Java-Anwendung erleichtern. Schließlich lernen Sie, wie Sie eine einfache Java-App kompilieren und ausführen.

Aktualisiert für Java 12 und die neue JShell

Diese Serie wurde für Java 12 aktualisiert und enthält eine kurze Einführung in das Neue jshell: ein interaktives Tool zum Erlernen von Java und zum Prototyping von Java-Code.

download Code abrufen Laden Sie den Quellcode herunter, zum Beispiel Anwendungen in diesem Tutorial. Erstellt von Jeff Friesen für JavaWorld.

Was ist java?

Sie können sich Java als eine universelle, objektorientierte Sprache vorstellen, die C und C ++ sehr ähnlich sieht, die jedoch einfacher zu verwenden ist und mit der Sie robustere Programme erstellen können. Leider gibt Ihnen diese Definition nicht viel Einblick in Java. Im Jahr 2000 beschrieb Sun Microsystems (Urheber der Java-Plattform) Java folgendermaßen: 

Java ist eine einfache, objektorientierte, netzwerkfähige, interpretierte, robuste, sichere, architekturneutrale, tragbare, leistungsstarke Multithread-Computersprache.

Betrachten wir jede dieser Definitionen separat.

Java ist eine einfache Sprache . Java wurde ursprünglich nach C und C ++ modelliert, abzüglich einiger möglicherweise verwirrender Funktionen. Zeiger, Vererbung mehrerer Implementierungen und Überladen von Operatoren sind einige C / C ++ - Funktionen, die nicht Teil von Java sind. Eine Funktion, die nicht in C / C ++ vorgeschrieben ist, aber für Java unerlässlich ist, ist eine Speicherbereinigungsfunktion, die Objekte und Arrays automatisch zurückfordert.

Java ist eine objektorientierte Sprache . Dank des objektorientierten Fokus von Java können Entwickler Java anpassen, um ein Problem zu lösen, anstatt uns zu zwingen, das Problem zu manipulieren, um Sprachbeschränkungen zu erfüllen. Dies unterscheidet sich von einer strukturierten Sprache wie C. Während Sie sich in Java beispielsweise auf Sparkontobjekte konzentrieren können, müssen Sie in C den Status des Sparkontos (z. B. einen Saldo) und das Verhalten (z. B. Ein- und Auszahlungen) getrennt betrachten.

Java ist eine netzwerkfähige Sprache . Die umfangreiche Netzwerkbibliothek von Java erleichtert die Verarbeitung von TCP / IP-Netzwerkprotokollen (Transmission Control Protocol / Internet Protocol) wie HTTP (HyperText Transfer Protocol) und FTP (File Transfer Protocol) und vereinfacht das Herstellen von Netzwerkverbindungen. Darüber hinaus können Java-Programme über Uniform Resource Locators (URLs) auf Objekte in einem TCP / IP-Netzwerk zugreifen, genauso einfach wie Sie über das lokale Dateisystem darauf zugreifen würden.

Java ist eine interpretierte Sprache . Zur Laufzeit wird ein Java-Programm indirekt auf der zugrunde liegenden Plattform (wie Windows oder Linux) über eine virtuelle Maschine (die eine Softwaredarstellung einer hypothetischen Plattform darstellt) und die zugehörige Ausführungsumgebung ausgeführt. Die virtuelle Maschine übersetzt die Bytecodes (Anweisungen und zugehörigen Daten) des Java-Programms durch Interpretation in plattformspezifische Anweisungen. Bei der Interpretation wird herausgefunden, was eine Bytecode-Anweisung bedeutet, und anschließend werden äquivalente plattformspezifische "vordefinierte" Anweisungen zur Ausführung ausgewählt. Die virtuelle Maschine führt dann diese plattformspezifischen Anweisungen aus.

Die Interpretation erleichtert das Debuggen fehlerhafter Java-Programme, da zur Laufzeit mehr Informationen zur Kompilierungszeit verfügbar sind. Die Interpretation ermöglicht es auch, den Verbindungsschritt zwischen den Teilen eines Java-Programms bis zur Laufzeit zu verzögern, was die Entwicklung beschleunigt.

Java ist eine robuste Sprache . Java-Programme müssen zuverlässig sein, da sie sowohl in verbraucher- als auch in geschäftskritischen Anwendungen verwendet werden, von Blu-ray-Playern bis hin zu Fahrzeugnavigations- oder Luftsteuerungssystemen. Zu den Sprachfunktionen, die Java robust machen, gehören Deklarationen, doppelte Typprüfung zur Kompilierungs- und Laufzeitzeit (um Probleme mit Versionsinkongruenzen zu vermeiden), echte Arrays mit automatischer Begrenzungsprüfung und das Weglassen von Zeigern. (Weitere Informationen zu Java-Sprachtypen, Literalen, Variablen und mehr finden Sie unter "Grundlegende Java-Sprachfunktionen".)

Ein weiterer Aspekt der Robustheit von Java besteht darin, dass Schleifen durch boolesche Ausdrücke anstelle von ganzzahligen Ausdrücken gesteuert werden müssen, wobei 0 falsch und ein Wert ungleich Null wahr ist. Beispielsweise lässt Java keine Schleife im C-Stil zu, z. B. while (x) x++;weil die Schleife möglicherweise nicht wie erwartet endet. Stattdessen müssen Sie explizit einen booleschen Ausdruck angeben, z. B. while (x != 10) x++;(was bedeutet, dass die Schleife ausgeführt wird, bis sie xgleich 10 ist).

Java ist eine sichere Sprache . Java-Programme werden in vernetzten / verteilten Umgebungen verwendet. Da Java-Programme auf die verschiedenen Plattformen eines Netzwerks migriert und auf diesen ausgeführt werden können, ist es wichtig, diese Plattformen vor bösartigem Code zu schützen, der Viren verbreiten, Kreditkarteninformationen stehlen oder andere böswillige Handlungen ausführen kann. Java-Sprachfunktionen, die Robustheit unterstützen (wie das Weglassen von Zeigern), funktionieren mit Sicherheitsfunktionen wie dem Java-Sandbox-Sicherheitsmodell und der Verschlüsselung mit öffentlichem Schlüssel. Zusammen verhindern diese Funktionen, dass Viren und anderer gefährlicher Code auf einer ahnungslosen Plattform Chaos anrichten.

Theoretisch ist Java sicher. In der Praxis wurden verschiedene Sicherheitslücken erkannt und ausgenutzt. Infolgedessen veröffentlichen Sun Microsystems und Oracle weiterhin Sicherheitsupdates.

Java ist eine architekturneutrale Sprache . Netzwerke verbinden Plattformen mit unterschiedlichen Architekturen, die auf verschiedenen Mikroprozessoren und Betriebssystemen basieren. Sie können nicht erwarten, dass Java plattformspezifische Anweisungen generiert und diese Anweisungen von allen Arten von Plattformen, die Teil eines Netzwerks sind, "verstanden" werden. Stattdessen generiert Java plattformunabhängige Bytecode-Anweisungen, die für jede Plattform leicht zu interpretieren sind (über die Implementierung der JVM).

Java ist eine tragbare Sprache . Architekturneutralität trägt zur Portabilität bei. Die Portabilität von Java umfasst jedoch mehr als plattformunabhängige Bytecode-Anweisungen. Beachten Sie, dass ganzzahlige Typgrößen nicht variieren dürfen. Beispielsweise muss der 32-Bit-Integer-Typ immer signiert sein und 32 Bit belegen, unabhängig davon, wo die 32-Bit-Integer verarbeitet wird (z. B. eine Plattform mit 16-Bit-Registern, eine Plattform mit 32-Bit-Registern oder eine Plattform mit 64-Bit-Registern). Die Bibliotheken von Java tragen ebenfalls zur Portabilität bei. Bei Bedarf bieten sie Typen, die Java-Code mit plattformspezifischen Funktionen auf möglichst portable Weise verbinden.

Java ist eine Hochleistungssprache . Die Interpretation ergibt ein Leistungsniveau, das normalerweise mehr als ausreichend ist. Für sehr leistungsstarke Anwendungsszenarien verwendet Java die Just-in-Time-Kompilierung, bei der interpretierte Bytecode-Befehlssequenzen analysiert und häufig interpretierte Befehlssequenzen zu plattformspezifischen Anweisungen kompiliert werden. Nachfolgende Versuche, diese Bytecode-Befehlssequenzen zu interpretieren, führen zur Ausführung äquivalenter plattformspezifischer Befehle, was zu einer Leistungssteigerung führt.

Java ist eine Multithread-Sprache . Um die Leistung von Programmen zu verbessern, die mehrere Aufgaben gleichzeitig ausführen müssen, unterstützt Java das Konzept der Thread-Ausführung . Beispielsweise verwendet ein Programm, das eine grafische Benutzeroberfläche (GUI) verwaltet, während es auf die Eingabe von einer Netzwerkverbindung wartet, einen anderen Thread, um das Warten durchzuführen, anstatt den Standard-GUI-Thread für beide Aufgaben zu verwenden. Dies hält die GUI ansprechbar. Mit den Synchronisationsprimitiven von Java können Threads Daten sicher untereinander kommunizieren, ohne die Daten zu beschädigen. (Siehe Thread-Programmierung in Java, die an anderer Stelle in der Java 101-Reihe erläutert wird.)

Java ist eine dynamische Sprache . Da die Verbindungen zwischen Programmcode und Bibliotheken zur Laufzeit dynamisch erfolgen, müssen sie nicht explizit verknüpft werden. Wenn sich ein Programm oder eine seiner Bibliotheken weiterentwickelt (z. B. zur Fehlerbehebung oder Leistungsverbesserung), muss ein Entwickler daher nur das aktualisierte Programm oder die aktualisierte Bibliothek verteilen. Obwohl dynamisches Verhalten dazu führt, dass bei einer Versionsänderung weniger Code verteilt werden muss, kann diese Verteilungsrichtlinie auch zu Versionskonflikten führen. Ein Entwickler entfernt beispielsweise einen Klassentyp aus einer Bibliothek oder benennt ihn um. Wenn ein Unternehmen die aktualisierte Bibliothek verteilt, schlagen vorhandene Programme fehl, die vom Klassentyp abhängen. Um dieses Problem erheblich zu reduzieren, unterstützt Java einen Schnittstellentyp, was wie ein Vertrag zwischen zwei Parteien ist. (Siehe Schnittstellen, Typen und andere objektorientierte Sprachfunktionen, die an anderer Stelle in der Java 101-Reihe erläutert werden.)

Das Auspacken dieser Definition lehrt uns viel über Java. Am wichtigsten ist, dass Java sowohl eine Sprache als auch eine Plattform ist. Weitere Informationen zu Java-Plattformkomponenten - nämlich der Java Virtual Machine und der Java-Ausführungsumgebung - finden Sie weiter unten in diesem Lernprogramm.

Drei Java-Editionen: Java SE, Java EE und Java ME

Sun Microsystems veröffentlichte im Mai 1995 das Java 1.0 Software Development Kit (JDK). Das erste JDK wurde zur Entwicklung von Desktop-Anwendungen und Applets verwendet, und Java wurde anschließend für die Programmierung von Unternehmensservern und Mobilgeräten entwickelt. Das Speichern aller erforderlichen Bibliotheken in einem einzigen JDK hätte das JDK zu groß für die Verteilung gemacht, insbesondere weil die Verteilung in den neunziger Jahren durch kleine CDs und langsame Netzwerkgeschwindigkeiten eingeschränkt war. Da die meisten Entwickler nicht jede letzte API benötigten (ein Entwickler von Desktopanwendungen würde kaum auf Java-APIs für Unternehmen zugreifen müssen), hat Sun Java in drei Haupteditionen unterteilt. Diese wurden schließlich als Java SE, Java EE und Java ME bekannt:

  • Java Platform, Standard Edition (Java SE) ist die Java-Plattform für die Entwicklung clientseitiger Anwendungen (die auf Desktops ausgeführt werden) und Applets (die in Webbrowsern ausgeführt werden). Beachten Sie, dass Applets aus Sicherheitsgründen nicht mehr offiziell unterstützt werden.
  • Java Platform, Enterprise Edition (Java EE ) ist die Java-Plattform, die auf Java SE aufbaut und ausschließlich zur Entwicklung unternehmensorientierter Serveranwendungen verwendet wird. Serverseitige Anwendungen umfassen Java-Servlets , bei denen es sich um Java-Programme handelt, die Applets ähneln, jedoch auf einem Server und nicht auf einem Client ausgeführt werden. Servlets entsprechen der Java-Servlet-API.
  • Java Platform, Micro Edition (Java ME) basiert ebenfalls auf Java SE. Es ist die Java-Plattform für die Entwicklung von MIDlets , bei denen es sich um Java-Programme handelt, die auf mobilen Informationsgeräten ausgeführt werden, und bei Xlets , bei denen es sich um Java-Programme handelt, die auf eingebetteten Geräten ausgeführt werden.

Java SE ist die Basisplattform für Java und steht im Mittelpunkt der Java 101-Serie. Codebeispiele basieren auf der neuesten Version von Java zum Zeitpunkt des Schreibens, Java 12.

Die Java-Plattform und JVM

Java ist sowohl eine Programmiersprache als auch eine Plattform zum Ausführen von kompiliertem Java-Code. Diese Plattform besteht hauptsächlich aus der JVM, enthält jedoch auch eine Ausführungsumgebung, die die Ausführung der JVM auf der zugrunde liegenden (nativen) Plattform unterstützt. Die JVM enthält mehrere Komponenten zum Laden, Überprüfen und Ausführen von Java-Code. Abbildung 1 zeigt, wie ein Java-Programm auf dieser Plattform ausgeführt wird. 

Jeff Friesen

Am oberen Rand des Diagramms befindet sich eine Reihe von Programmklassendateien, von denen eine als Hauptklassendatei bezeichnet wird. Ein Java-Programm besteht mindestens aus der Hauptklassendatei, der ersten Klassendatei, die geladen, überprüft und ausgeführt wird.

Die JVM delegiert das Laden von Klassen an ihre Classloader-Komponente. Klassenladeprogramme laden Klassendateien aus verschiedenen Quellen, z. B. Dateisystemen, Netzwerken und Archivdateien. Sie isolieren die JVM von den Feinheiten des Klassenladens.

Eine geladene Klassendatei wird im Speicher gespeichert und als aus der ClassKlasse erstelltes Objekt dargestellt . Nach dem Laden überprüft der Bytecode-Prüfer die verschiedenen Bytecode-Anweisungen, um sicherzustellen, dass sie gültig sind und die Sicherheit nicht beeinträchtigen.

Wenn die Bytecodes der Klassendatei nicht gültig sind, wird die JVM beendet. Andernfalls interpretiert seine Interpreterkomponente den Bytecode Befehl für Befehl. Die Interpretation identifiziert Bytecode-Anweisungen und führt äquivalente native Anweisungen aus.

Einige Bytecode-Befehlssequenzen werden häufiger ausgeführt als andere. Wenn der Interpreter diese Situation erkennt, kompiliert der Just-in-Time-Compiler (JIT) der JVM die Bytecode-Sequenz zur schnelleren Ausführung in nativen Code.

Während der Ausführung stößt der Interpreter normalerweise auf eine Anforderung, den Bytecode einer anderen Klassendatei (die zum Programm oder zu einer Bibliothek gehört) auszuführen. In diesem Fall lädt der Klassenladeprogramm die Klassendatei und der Bytecode-Prüfer überprüft den Bytecode der geladenen Klassendatei, bevor er ausgeführt wird. Während der Ausführung können Bytecode-Anweisungen die JVM auffordern, eine Datei zu öffnen, etwas auf dem Bildschirm anzuzeigen, einen Ton zu erzeugen oder eine andere Aufgabe auszuführen, die die Zusammenarbeit mit der nativen Plattform erfordert. Die JVM antwortet mit ihrer JNI-Brückentechnologie (Java Native Interface), um mit der nativen Plattform zu interagieren und die Aufgabe auszuführen.