Das Ziel dieses Kurses ist es, Ihnen bei der effektiveren Verwendung von Java zu helfen. Es werden einige erweiterte Themen diskutiert, einschließlich Objekterstellung, Parallelität, Serialisierung, Reflexion und anderen fortgeschrittenen Merkmalen. Dieser Kurs wird Ihre Reise der Java -Kompetenz leiten.
1. Einführung
Im Ranking der Tiobe -Programmiersprache ist die von Sun 1995 entwickelte Java -Sprache eine der am häufigsten verwendeten Programmiersprachen der Welt. Als allgemeine Programmiersprache ist die Java -Sprache für Softwareentwicklungsingenieure sehr attraktiv, da die Umgebung und die Laufzeit -Umgebung, die einfache Syntax, die Rich -Plattform -Unterstützung (gleichzeitig geschrieben, überall ausgeführt) und äußerst aktiver Community -Support.
In dieser Artikelreihe wird erweiterte Inhalte im Zusammenhang mit Java behandelt, sodass der Leser bereits grundlegendes Sprachwissen verfügt. Dies ist kein vollständiges Referenzhandbuch, sondern ein umfassender Leitfaden, um Ihre Fähigkeiten auf die nächste Ebene zu bringen.
Dieser Kurs enthält eine große Anzahl von Codeschnippets. Um Vergleiche durchzuführen, geben einige andere Parteien gleichzeitig Beispiele für Java 7 und Java 8 an.
2. Beispielkonstruktion
Als objektorientierte Sprache ist Objekterstellung vielleicht eines der wichtigsten Konzepte in der Java-Sprache. Ein Konstruktor spielt eine wichtige Rolle bei der Initialisierung von Objektinstanzen, und Java bietet eine Vielzahl von Möglichkeiten, Konstruktoren zu definieren.
2.1 implizite (generierte) Konstruktionsmethode
Mit Java können keine Konstruktoren beim Definieren von Klassen deklariert werden, und dies bedeutet nicht, dass es keinen Konstruktor gibt. Schauen wir uns die Definition der folgenden Klasse an:
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasse Noconstructor {}Diese Klasse definiert keinen Konstruktor, aber der Java -Compiler generiert implizit einen dafür, sodass wir das neue Schlüsselwort zum Erstellen neuer Objektinstanzen verwenden können.
endgültiger Noconstructor NoconstructorinStance = neuer Noconstructor ();
2.2 parameterlose Konstruktionsmethode
Der parameterlose Konstruktor ist der einfachste Weg, um die Java -Kompilierung zu ersetzen und Konstruktoren durch explizite Erklärungen zu erzeugen.
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasse noargconstructor {public noargconstructor () {// Constructor Body hier}}Beim Erstellen einer neuen Objektinstanz mit dem neuen Schlüsselwort wird der obige Konstruktor aufgerufen.
2.3 Parameterähnliche Konstruktionsmethode
Die Parameterkonstruktionsmethode ist die interessanteste und am häufigsten verwendete, und die Erstellung neuer Instanzen wird durch Angabe von Parametern angepasst. Das folgende Beispiel definiert einen Konstruktor mit zwei Parametern.
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasse Konstruktor mit
In diesem Szenario müssen bei Verwendung des neuen Schlüsselworts zum Erstellen einer Instanz gleichzeitig zwei auf der Konstruktionsmethode definierte Parameter bereitgestellt werden.
endgültiger Konstruktor mit Konstruktor mit dem Konstruktor mit dem Konstruktor mit dem Konstruktor ("arg1", "arg2");Interessanterweise können Konstruktoren durch dieses Schlüsselwort einander aufgerufen werden. In der Praxis wird empfohlen, mehrere Konstruktoren zu ketten, indem sie diese verwenden, um die Code -Duplikation zu verringern und einen einzigen Initialisierungseintrag basierend auf dem Objekt zu haben. Beispielsweise definiert der folgende Code einen Konstruktor mit nur einem Parameter.
public constructor withargumente (endgültig string arg1) {this (arg1, null);}2.4 Initialisieren Sie den Codeblock
Neben dem Bau von Methoden bietet Java auch die Logik zur Initialisierung durch Initialisierung von Codeblöcken. Obwohl diese Verwendung selten ist, ist es nicht schädlich, mehr darüber zu wissen.
Paket com.javacodegeeks.advanced.Construction; öffentliche KlasseninitializationBlock {{// Initialisierungscode hier}}Andererseits kann die Initialisierung von Codeblöcken auch als implizite Konstruktionsmethoden ohne Parameter angesehen werden. In einer bestimmten Klasse können mehrere Initialisierungscodeblöcke definiert werden und werden in der Reihenfolge aufgerufen, die sie bei der Ausführung im Code befinden, wie im folgenden Code gezeigt:
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasseninitialisierungsblocks {{// Initialisierungscode hier} {// Initialisierungscode hier}}Die wirklich initialisierenden Codeblöcke müssen den Konstruktor nicht ersetzen, aber sie können gleichzeitig erscheinen. Denken Sie jedoch daran, dass der Initialisierungscode ausgeführt wird, bevor der Aufruf der Konstruktormethode in Kürze erfolgt.
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasse InitializationBlockAndConstructor {{// Initialisierungscode hier} public initializationBlock undConstructor () {}}2.5 Gewährleistung der Konstruktion von Standardwerten
Java bietet eine bestimmte Initialisierungsgarantie, und Programmierer können das Initialisierungsergebnis direkt verwenden. Nicht initialisierte Instanzen und Klassenvariablen (Statik) werden automatisch in die entsprechenden Standardwerte initialisiert.
Geben Sie den Standardwert ein
BooleanFalse
Byte0
Short0
int0
long0l
char/u0000
float0.0f
double0.0d
Objektreferenz NULL
Tabelle 1
Wir verwenden das folgende Beispiel, um die Standardwerte in der obigen Tabelle zu überprüfen:
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasseninitialisierung mit privates Byte -Bytemember; privates Kurzschluss; Privat intMember; privat lang langes langes langes langes; privates Charmit Charmeer; Privat Float Floatmitglied; privates Doppelmember; privates Objekt Referencemember; public initializationWithDefaults () {System.out.println ("booleanmember =" + booleanMember); System.out.println ("bytemember =" + bytemember); System.out.println ("ShortMember =" + ShortMember); System.out.println ("intmember =" + intmember); System.out.println ("longmember =" + longMember); System.out.println ("charmember =" + charakter.CodePointat (neu [] {charmember}, 0)); System.out.println ("floatMember =" + floatMember); System.out.println ("DoubleMember =" + DoubleMember); System.out.println ("Referencemember =" + Referencemember); }}Nach dem Instanziieren des Objekts mit dem neuen Schlüsselwort:
endgültige Initialisierung mit
Sie können das Ausgabeergebnis aus der Konsole wie folgt sehen:
booleanMember = falseByTemember = 0Shortmember = 0IntMember = 0longMember = 0Charmember = 0FloatMember = 0,0DouBlemember = 0,0Referencemember = NULL
2.6 Sichtbarkeit
Der Konstruktor folgt den Sichtbarkeitsregeln von Java und kann feststellen, ob der Konstruktor in anderen Klassen über Zugriffskontrollmodifikatoren aufgerufen werden kann.
Sichtbarkeit von Modifikatorpaket Sichtbarkeit Sichtbarkeit öffentlich Sichtbarkeit
öffentlich sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbare sichtbart
geschützter sichtbares sichtbares, sichtbares unsichtbares Unsichtbar
<Nein Modifikator> sichtbar, nicht sichtbar, nicht sichtbar
Private unsichtbare unsichtbare unsichtbare unsichtbare Tabelle 2
2.7 Müllrecycling
Java (JVM zu präzise) verfügt über einen automatischen Müllsammlermechanismus. Einfach ausgedrückt, wenn ein neues Objekt erstellt wird, wird es seine Intrinsik automatisch zuweisen. Wenn das Objekt dann nicht mehr verwiesen wird, wird es automatisch zerstört und der entsprechende Speicher wird recycelt.
Die Java -Müllsammlung nimmt einen Generationen -Recycling -Mechanismus an und basiert auf der Annahme, dass "die meisten Objekte ein kurzes Leben haben" (dh sie werden nicht bald nach dem Erstellen des Objekts rezitiert, damit sie sicher zerstört werden können). Die meisten Programmierer glauben gewöhnlich, dass die Erstellung von Objekten in Java sehr ineffizient ist, daher sollten sie die Schaffung neuer Objekte so weit wie möglich vermeiden. Tatsächlich ist dieses Verständnis falsch. Der Aufwand des Erstellens von Objekten in Java ist ziemlich niedrig und schnell. Der riesige Overhead der realen Generation sind unnötige langfristige Überlebensobjekte, sodass sie schließlich in das Alter migriert werden und dazu führen, dass die Welt auftritt.
2.8 Objekt Finalizer
Wir haben über die Themen im Zusammenhang mit Konstruktionsmethoden und Objektinitialisierung gesprochen, aber wir haben ihre negative Seite nicht erwähnt: Objektzerstörung. Hauptsächlich, weil Java Müllsammlungsmechanismen verwendet, um den Lebenszyklus von Objekten zu verwalten, unnötige Objekte zu zerstören und das erforderliche Gedächtnis zur Verantwortung der Müllsammlung zu verantwortlich.
Java bietet jedoch weiterhin ein weiteres Merkmal, das einem Destructor Finalizer ähnelt, der die Verantwortung für die Reinigung mehrerer Ressourcen übernimmt. Finalizer wird im Allgemeinen als gefährliche Sache angesehen (da er eine Vielzahl von Nebenwirkungen und Leistungsproblemen mitbringen kann). Normalerweise ist Finalizer nicht erforderlich. Versuchen Sie daher, dies zu vermeiden (außer in seltenen Szenarien, die eine große Anzahl nativer Objekte enthalten). Die in Java 7 eingeführte Try-with-Ressources-Syntax und autococlosenbare Schnittstelle können als Alternativen zu Finalizern verwendet werden, und der folgende prägnante Code kann geschrieben werden:
try (Final InputStream in = Dateien.NewInputStream (Pfad)) {// Code hier}1. Statische Initialisierung
Oben haben wir die Konstruktion und Initialisierung von Klasseninstanzen gelernt. Darüber hinaus unterstützt Java die Initialisierungskonstruktion auf Klassenebene, die als statische Initialisierung bezeichnet wird. Die statische Initialisierung ähnelt dem oben beschriebenen Initialisierungscode -Block, mit der Ausnahme, dass zusätzliche statische Schlüsselwortmodifikationen vorhanden sind. Es ist zu beachten, dass die statische Initialisierung nur einmal ausgeführt wird, wenn die Klasse geladen ist. Beispiele sind wie folgt:
Ähnlich wie bei der Initialisierungscodeblöcke können mehrere statische Initialisierungsblöcke in einer Klasse definiert werden, und ihre Position in der Klasse bestimmt die Reihenfolge, in der sie bei der Initialisierung ausgeführt werden. Beispiele sind wie folgt;
Paket com.javacodegeeks.advanced.Construction; öffentliche Klasse staticInitializationBlocks {static {// statischer Initialisierungscode hier} static {// statischer Initialisierungscode hier}}}Da statische Initialisierungsblöcke durch mehrere parallel ausgeführte Threads ausgelöst werden können (wenn die Klasse ursprünglich geladen wird), stellt die JVM-Laufzeit sicher, dass der initialisierte Code nur einmal auf eine Thread-sicher ausgeführt wird.
4. Konstruktormodus
In der Java-Community wurde im Laufe der Jahre eine Vielzahl von leicht verständlichen Konstruktor-Mustern (Creator) in der Java-Community eingeführt. Im Folgenden lernen wir einige der beliebtesten: Singleton -Modus, Hilfsklassenmodus, Werksmodus und Abhängigkeitsinjektion (auch als Kontrollinversion bezeichnet).
4.1 Singleton -Modus
Singleton ist eine lange Geschichte, aber umstrittenes Modell in der Softwareentwicklungsgemeinschaft. Das Kernkonzept des Singleton -Musters besteht darin, sicherzustellen, dass zu jeder Zeit eine bestimmte Klasse erstellt wird. Es klingt zwar einfach, aber es gibt viele Diskussionen darüber, wie Objekte korrekt und threadssicher erstellen können. Der folgende Code zeigt eine einfache Version der Singleton -Muster -Implementierung:
Paket com.javacodegeeks.advanced.construction.Patterns; öffentliche Klasse Naivesingleton {private statische Naivesingleton -Instanz; private naivesingleton () {} public static naivesingleton getInstance () {if (instance == null) {instance = new naivesingleton (); } return Instance; }}Es gibt mindestens ein Problem mit dem obigen Code: In einem Szenario mit mehreren Thread-Parallelität können mehrere Objekte erstellt werden. Ein vernünftiger Weg, um die Belastung zu implementieren (aber nicht verzögert), besteht darin, die statische Eigenschaft der Klasse zu verwenden. wie folgt:
endgültige Eigenschaft der Klasse.Package com.javacodegeeks.advanced.construction.Patterns; Public Class Eagersingleton {private statische endgültige Eagersingleton Instance = new eagersingleton (); private eagersingleton () {} public static eagersingleton getInstance () {return Instance; }}Wenn Sie keine wertvollen Ressourcen verschwenden möchten und Singleton -Objekte nur dann erstellen möchten, wenn sie wirklich benötigt werden, müssen Sie eine explizite Synchronisationsmethode verwenden. Diese Methode kann die Parallelität in Umgebungen mit mehreren Threads verringern (weitere Details zur Parallelität von Java werden in den Best Practices mit 9-Konkurrenten in Java beschrieben).
Paket com.javacodegeeks.advanced.construction.Patterns; öffentliche Klasse Lazysingleton {private statische Lazysingleton -Instanz; private lazysingleton () {} public static synchronisierte lazysingleton getInstance () {if (instance == null) {instance = new lazysingleton (); } return Instance; }}Heutzutage werden Singleton -Muster in vielen Szenarien nicht mehr als gute Wahl angesehen, da sie den Code weniger leicht zu testen. Darüber hinaus macht die Erzeugung des Abhängigkeitsinjektionsmodus auch den Singleton -Modus unnötig.
4.2 Werkzeuge/Hilfsklassen
Das Werkzeugklassen/Hilfsklassenmuster ist bei Java -Entwicklern sehr beliebt. Sein Kernkonzept besteht darin, nicht-intitialisierte Klassen (durch Deklaration privater Konstrukteure) zu verwenden, optionale endgültige (weitere Details zur Deklaration der endgültigen Klassen werden in Java Advanced 3-Class- und Schnittstellendesign) Keywords und statische Methoden eingeführt. Beispiele sind wie folgt:
Paket com.javacodegeeks.advanced.construction.Patterns; öffentliche endgültige Klasse HelperClass {private helperClass () {} public static void HelperMethod1 () {// Methode Body hier} hier}Viele erfahrene Entwickler glauben, dass dieses Muster Werkzeugkurse zu einem Container für verschiedene irrelevante Methoden machen wird. Da einige Methoden keine geeignete Platzierung haben, sondern von anderen Klassen verwendet werden müssen, werden sie fälschlicherweise in die Werkzeugklasse eingebaut. Dieses Design sollte auch in den meisten Szenarien vermieden werden: Es wird immer bessere Möglichkeiten geben, den Code wiederzuverwenden und den Code klar und präzise zu halten.
4.3 Fabrikmodell
Das Werksmodell hat sich als äußerst leistungsfähiges Werkzeug für Entwickler erwiesen, und es gibt viele Möglichkeiten, es in Java zu implementieren: Fabrikmethoden und abstrakte Fabriken. Am einfachsten ist es, die statische Methode zu verwenden, um eine Instanz einer bestimmten Klasse (Fabrikmethode) zurückzugeben, wie folgt:
paket com.javacodegeeks.advanced.construction.patterns; public class book {private book (endgültiger String -Titel) {} public static book Newbook (endgültiger String -Titel) {return New Book (Titel); }}Obwohl die Verwendung dieser Methode die Lesbarkeit des Codes verbessern kann, ist es oft umstritten, dass es schwierig ist, der Newbook Factory -Methode reichhaltigere Szenarien zu geben. Eine andere Möglichkeit, das Werksmuster zu implementieren, besteht darin, Schnittstellen oder abstrakte Klassen (abstrakte Fabriken) zu verwenden. Wie folgt definieren wir eine Fabrikschnittstelle:
public interface bookfactory {book Newbook ();}Abhängig von der Bildergalerie können wir viele verschiedene neue Book -Implementierungen haben:
Public Class Library Implementle BookFactory {@Override Public Book Newbook () {return New Paperbook (); }} public class Kindlelibrary implementiert BookFactory {@Override public book Newbook () {return New KindLebook (); }}Jetzt blockieren verschiedene Implementierungen von Bookfactory die Unterschiede in bestimmten Büchern, bieten jedoch eine allgemeine neue Buchmethode.
4.4 Abhängigkeitsinjektion
Die Abhängigkeitsinjektion (auch als Kontrollinversion bezeichnet) wird von Klassenentwicklern als gute Designpraxis angesehen: Wenn einige Klasseninstanzen von Instanzen anderer Klassen abhängen, sollten die abhängigen Instanzen, die abhängig sind, durch Konstruktormethoden (oder Setzermethoden, Richtlinien usw.) und nicht durch die Instanz selbst bereitgestellt (injiziert) werden. Schauen wir uns den folgenden Code an:
Paket com.javacodegeeks.advanced.construction.Patterns; import Java.text.DateFormat; import Java.util.Date; öffentliche Klasse abhängig {private endgültige DatumFormat Format = DateFormat.getDateinstance (); öffentliches Zeichenfolgenformat (Enddatum) {return format.format (Datum); }}Die abhängige Klasse erfordert eine Instanz der DateFormat -Klasse und wird durch DateFormat.getDateinstance () erhalten, wenn das Objekt instanziiert. Ein besserer Weg sollte dasselbe tun, indem sie die Parameter der Methode konstruieren:
paket com.javacodegeeks.advanced.construction.Patterns; import Java.text.DateFormat; Import Java.util.Date; öffentliche Klasse -Abhängigkeit {private endgültige DatumFormat -Format; public abhängig (endgültiges DateFormat -Format) {this.format = format; } public String -Format (endgültiges Datum) {return format.format (Datum); }}Im obigen Beispiel werden alle Abhängigkeiten der Klasseninstanz extern bereitgestellt, sodass das DateFormat und das Schreiben von Testcode einfach zu beschreiben sind.