Le but de ce cours est de vous aider à utiliser Java plus efficacement. Il y a des sujets avancés abordés, notamment la création d'objets, la concurrence, la sérialisation, la réflexion et d'autres fonctionnalités avancées. Ce cours guidera votre voyage de compétence Java.
1. Introduction
Dans le classement du langage de programmation Tiobe, le langage Java développé par Sun en 1995 est l'un des langages de programmation les plus utilisés au monde. En tant que langage de programmation général, le langage Java est très attrayant pour les ingénieurs de développement de logiciels en raison de sa puissante boîte à outils et de son environnement d'exécution, de sa syntaxe simple, de son support de plate-forme riche (écrit immédiatement, de l'exécution partout) et d'un support communautaire extrêmement actif.
Dans cette série d'articles, le contenu avancé lié à Java est couvert, il est donc supposé que le lecteur a déjà des connaissances linguistiques de base. Ce n'est pas un manuel de référence complet, mais un guide exhaustif pour faire passer vos compétences au niveau supérieur.
Ce cours contient un grand nombre d'extraits de code. Afin de faire des comparaisons, certaines autres parties fourniront des exemples de Java 7 et Java 8 en même temps.
2. Exemple de construction
En tant que langue orientée objet, la création d'objets est peut-être l'un des concepts les plus importants de la langue java. Un constructeur joue un rôle important dans l'initialisation des instances d'objet, et Java fournit une variété de façons de définir les constructeurs.
2.1 Méthode de construction implicite (générée)
Java ne permet de déclarer aucun constructeur lors de la définition des classes, ce qui ne signifie pas qu'il n'y a pas de constructeur. Regardons la définition de la classe suivante:
package com.javacodegeeks.advanced.construction; classe publique noconstructor {}Cette classe ne définit pas un constructeur, mais le compilateur Java en générera implicitement un pour cela, ce qui nous permet d'utiliser le nouveau mot-clé pour créer de nouvelles instances d'objet.
noconstructor final noconstructorinstance = nouveau noconstructor ();
2.2 Méthode de construction sans paramètres
Le constructeur sans paramètre est le moyen le plus simple de remplacer la compilation Java et de générer des constructeurs par des déclarations explicites.
package com.javacodegeeks.advanced.construction; classe publique noargonstructor {public noargonstructor () {// corps constructeur ici}}Lors de la création d'une nouvelle instance d'objet à l'aide du nouveau mot-clé, le constructeur ci-dessus sera appelé.
2.3 Méthode de construction de type paramètre
La méthode de construction de paramètres est la plus intéressante et la plus utilisée, et la création de nouvelles instances est personnalisée en spécifiant les paramètres. L'exemple suivant définit un constructeur avec deux paramètres.
package com.javacodegeeks.advanced.construction; classe publique constructeurwitharguments {public constructorwitharguments (chaîne finale arg1, chaîne finale arg2) {// corps de constructeur ici}}Dans ce scénario, lors de l'utilisation du nouveau mot-clé pour créer une instance, deux paramètres définis sur la méthode de construction doivent être fournis en même temps.
Constructeur final WithithArguments ConstructorwithArguments = new ConstructorWithArguments ("Arg1", "Arg2");Fait intéressant, les constructeurs peuvent être appelés les uns aux autres via ce mot-clé. En pratique, il est recommandé de chaîner plusieurs constructeurs en utilisant cela pour réduire la duplication de code et pour avoir une seule entrée d'initialisation basée sur l'objet. Par exemple, le code suivant définit un constructeur avec un seul paramètre.
Constructeur publicwithArguments (chaîne finale Arg1) {this (arg1, null);}2.4 Initialiser le bloc de code
En plus de construire des méthodes, Java fournit également la logique pour initialiser en initialisant les blocs de code. Bien que cette utilisation soit rare, il n'est pas nocif d'en savoir plus.
package com.javacodegeeks.advanced.construction; classe publique initialisationblock {{// code d'initialisation ici}}D'un autre côté, l'initialisation des blocs de code peut également être considérée comme des méthodes de construction implicites sans paramètres. Dans une classe spécifique, plusieurs blocs de code d'initialisation peuvent être définis, et ils sont appelés dans l'ordre dans lequel ils sont dans le code lorsqu'ils sont exécutés, comme indiqué dans le code suivant:
package com.javacodegeeks.advancé
L'initialisation des blocs de code ne doit pas remplacer le constructeur, mais ils peuvent apparaître simultanément. Mais n'oubliez pas que le code d'initialisation sera exécuté avant l'appel de la méthode du constructeur.
package com.javacodegeeks.advanced.construction; classe publique InitialisationBlockAndConstructor {{// Code d'initialisation ici} public InitiationBlockAndConstructor () {}}2.5 Assurer la construction de valeurs par défaut
Java fournit une garantie d'initialisation définie et les programmeurs peuvent utiliser directement le résultat d'initialisation. Les instances et les variables de classe non initialisées (statistiques) seront automatiquement initialisées aux valeurs par défaut correspondantes.
Tapez la valeur par défaut
booléenfalse
byte0
Short0
int0
Long0L
char / u0000
float0.0f
Double0.0d
Référence d'objet NULL
Tableau 1
Nous utilisons l'exemple suivant pour vérifier les valeurs par défaut dans le tableau ci-dessus:
package com.javacodegeeks.advanced.construction; Initialisation de classe publique WithDithDefaults {private boolean booleanmembe; Byte privé Bytemember; Retour de court-métrage privé; private intmember; Private Long Long Longmember; Charmed privé Charmember; Float Floatmember privé; Private Double Doublète; RÉFÉRENCE D'OBJET PRIVÉ; Initialisation publique withDefaults () {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 =" + caractères.codepointat (new char [] {charmember}, 0)); System.out.println ("FloatMember =" + FloatMember); System.out.println ("Doublembember =" + doublémeur); System.out.println ("ReferenceMember =" + RefercenceMember); }}Après avoir instancié l'objet en utilisant le nouveau mot-clé:
Initialisation finale avec l'initialisation desfaults avecfaults = nouvelle initialisation withDefaults (),
Vous pouvez voir le résultat de sortie de la console comme suit:
BooleanMember = FalseByteMember = 0ShortMember = 0IntMember = 0LongMember = 0Charmbember = 0floatMember = 0,0Doublebblember = 0.0ReferenceMember = Null
2.6 Visibilité
Le constructeur suit les règles de visibilité de Java et peut déterminer si le constructeur peut être appelé dans d'autres classes via des modificateurs de contrôle d'accès.
Visibilité de la sous-classe du colis modificateur Visibilité publique
public visible visible visible visible visible visible
protégé visible visible invisible invisible invisible
<Pas de modificateur> visible, pas visible, pas visible
Invisible invisible privé invisible Tableau invisible 2
2.7 Recyclage des ordures
Java (JVM pour être précis) a un mécanisme de collecte de déchets automatique. Autrement dit, lorsqu'un nouvel objet est créé, il allouera automatiquement ses intrinsèques; Ensuite, lorsque l'objet n'est plus référencé, ils seront automatiquement détruits et la mémoire correspondante sera recyclée.
Java Garbage Collection adopte un mécanisme de recyclage générationnel et est basé sur l'hypothèse que "la plupart des objets ont une courte durée de vie" (c'est-à-dire qu'ils ne seront pas récités peu de temps après la création de l'objet, afin qu'ils puissent être détruits en toute sécurité). La plupart des programmeurs croient habituellement que la création d'objets en Java est très inefficace, ils devraient donc éviter la création de nouveaux objets autant que possible. En fait, cette compréhension est erronée. Les frais généraux de la création d'objets en Java sont assez bas et rapides. L'énorme frais généraux de la génération réelle est des objets de survie à long terme inutiles, ils seront donc finalement migrés vers la vieillesse et provoqueront un arrêt du monde.
2.8 Finaliseurs d'objet
Nous avons parlé des sujets liés aux méthodes de construction et à l'initialisation des objets, mais nous n'avons pas mentionné leur côté négatif: la destruction des objets. Principalement parce que Java utilise des mécanismes de collecte des ordures pour gérer le cycle de vie des objets, détruire des objets inutiles et libérer la mémoire requise devient la responsabilité de la collecte des ordures.
Cependant, Java fournit toujours une autre caractéristique similaire à un finalizer destructor, qui assume la responsabilité de nettoyer plusieurs ressources. Finalizer est généralement considéré comme une chose dangereuse (car elle peut apporter une variété d'effets secondaires et de problèmes de performances). Habituellement, Finalizer n'est pas nécessaire, alors essayez de l'éviter (sauf dans des scénarios rares qui contiennent un grand nombre d'objets natifs). La syntaxe TRY-With-Resources et l'interface autoclosable introduite dans Java 7 peuvent être utilisées comme alternatives aux finalisateurs, et le code concis suivant peut être écrit:
essayez (final inputStream dans = files.newinputStream (path)) {// code ici}3. Initialisation statique
Ci-dessus, nous avons appris la construction et l'initialisation des instances de classe. De plus, Java prend également en charge la construction d'initialisation au niveau de la classe, appelée initialisation statique. L'initialisation statique est similaire au bloc de code d'initialisation décrit ci-dessus, sauf qu'il existe des modifications de mots clés statiques supplémentaires. Il convient de noter que l'initialisation statique ne sera effectuée qu'une fois que la classe sera chargée. Les exemples sont les suivants:
Semblable à l'initialisation des blocs de code, plusieurs blocs d'initialisation statiques peuvent être définis dans une classe et leur position dans la classe détermine l'ordre dans lequel ils sont exécutés à l'initialisation. Les exemples sont les suivants;
package com.javacodegeeks.advanced.construction; public class staticinitializationblocks {static {// code d'initialisation statique ici} statique {// code d'initialisation statique ici}}Étant donné que les blocs d'initialisation statiques peuvent être déclenchés par plusieurs threads exécutés en parallèle (lorsque la classe est initialement chargée), le temps d'exécution JVM garantit que le code initialisé n'est exécuté qu'une seule fois de manière filiale.
4. Mode constructeur
Une variété de modèles de constructeur (créateur) faciles à comprendre ont été présentés à la communauté Java au fil des ans. Ci-dessous, nous apprendrons quelques-unes des plus populaires: mode singleton, mode de classe auxiliaire, mode d'usine et injection de dépendance (également connue sous le nom d'inversion de contrôle).
4.1 Mode singleton
Singleton est une longue histoire mais un modèle controversé dans la communauté de développement de logiciels. Le concept principal du modèle singleton est de s'assurer qu'à tout moment, une classe donnée n'est créée qu'un seul objet. Bien que cela semble simple, il y a beaucoup de discussions sur la façon de créer des objets d'une manière correcte et filiale. Le code suivant montre une version simple de l'implémentation du modèle Singleton:
package com.javacodegeeks.advanced.construction.Patterns; public class naivesingleton {private static naivesingleton instance; naïves privées () {} public static naivesingleton getInstance () {if (instance == null) {instance = new naivesingleton (); } return instance; }}Il y a au moins un problème avec le code ci-dessus: plusieurs objets peuvent être créés dans un scénario de concurrence multithread. Un moyen raisonnable de mettre en œuvre (mais pas de chargement retardé) consiste à utiliser la propriété statique «final »de la classe. comme suit:
Propriété finale de la classe.package com.javacodegeeks.advanced.construction.patterns; public class eAgersingleton {private static final eagerSingleton instance = new eagerSingleton (); private eAgerSingleton () {} public static eagerSingleton getInstance () {return instance; }}Si vous ne voulez pas gaspiller des ressources précieuses et que vous voulez que les objets Singleton soient créés uniquement lorsqu'ils sont vraiment nécessaires, vous devez utiliser une méthode de synchronisation explicite. Cette méthode peut réduire la concurrence dans des environnements multipliés (plus de détails sur la concurrence de Java seront décrits dans les meilleures pratiques avancées à 9 curances de Java).
package com.javacodegeeks.advanced.construction.Patterns; public class Lazysingleton {instance privée statique de Lazysingleton; privé lazysingleton () {} public statique synchronisé lazysingleton getInstance () {if (instance == null) {instance = new Lazysingleton (); } return instance; }}De nos jours, les modèles Singleton ne sont plus considérés comme un bon choix dans de nombreux scénarios car ils rendent le code moins facile à tester. De plus, la génération de mode d'injection de dépendance rend également le mode Singleton inutile.
4.2 outils / classes auxiliaires
Le modèle de classe d'outils / classe d'aide est très populaire parmi les développeurs Java. Son concept principal est d'utiliser des classes non instialisées (en déclarant les constructeurs privés), des mots clés Final Final (plus de détails sur la déclaration des classes finales seront introduits dans Java Advanced 3 classe et conception d'interface) et des méthodes statiques. Les exemples sont les suivants:
package com.javacodegeeks.advancé
De nombreux développeurs expérimentés croient que ce modèle fera des classes d'outils un conteneur pour diverses méthodes non pertinentes. Parce que certaines méthodes n'ont pas de placement approprié mais doivent être utilisées par d'autres classes, elles seront placées à tort dans la classe d'outils. Cette conception doit également être évitée dans la plupart des scénarios: il y aura toujours de meilleurs moyens de réutiliser le code, en gardant le code clair et concis.
4.3 Modèle d'usine
Le modèle d'usine s'est avéré être un outil extrêmement puissant pour les développeurs, et il existe de nombreuses façons de la mettre en œuvre en Java: méthodes d'usine et usines abstraites. L'exemple le plus simple est d'utiliser la méthode statique pour renvoyer une instance d'une classe spécifique (méthode d'usine), comme suit:
package com.javacodegeeks.advanced.construction.patterns; livre de classe publique {livre privé (titre de chaîne finale) {} public static newbook (titre de chaîne finale) {return nouveau livre (titre); }}Bien que l'utilisation de cette méthode puisse améliorer la lisibilité du code, il est souvent controversé qu'il est difficile de donner des scénarios plus riches à la méthode de Newbook Factory. Une autre façon d'implémenter le modèle d'usine est d'utiliser des interfaces ou des classes abstraites (usines abstraites). Comme suit, nous définissons une interface d'usine:
Interface publique BookFactory {book newbook ();}Selon la galerie de photos, nous pouvons avoir de nombreuses implémentations de newbook différentes:
La bibliothèque de classe publique implémente BookFactory {@Override Public Book newbook () {return new Paperbook (); }} classe publique KindleLiBrary implémente bookFactory {@Override public livre newbook () {return new KindleBook (); }}Désormais, différentes implémentations de BookFactory bloquent les différences dans des livres spécifiques, mais fournissent une méthode de net newbook.
4.4 Injection de dépendance
L'injection de dépendance (également connue sous le nom d'inversion de contrôle) est considérée par les concepteurs de classe comme une bonne pratique de conception: si certaines instances de classe dépendent des cas d'autres classes, les instances qui dépendent doivent être fournies (injectées) via des méthodes de constructeur (ou des méthodes de secteur, des politiques, etc.), plutôt que créées par l'instance elle-même. Jetons un coup d'œil au code suivant:
package com.javacodegeeks.advanced.construction.patterns; import java.text.dateFormat; import java.util.date; public class Dependent {private final dateFormat format = dateFormat.getDateInstance (); Format de chaîne publique (date de date finale) {return format.format (date); }}La classe dépendante nécessite une instance de la classe DateFormat et est obtenue par DateFormat.getDateInstance () lors de l'instanciation de l'objet. Une meilleure façon devrait faire la même chose en construisant les paramètres de la méthode:
package com.javacodegeeks.advanced.construction.patterns; import java.text.dateFormat; import java.util.date; public de la classe publique {format final de date final privé; Public Dependent (format final DateFormat) {this.format = format; } Format de chaîne publique (date finale de date) {return format.format (date); }}Dans l'exemple ci-dessus, toutes les dépendances de l'instance de classe sont fournies en externe, ce qui facilite la modification de DateFormat et le code de test facile à écrire.