Si nous appelons la méthode GetPackage sur l'objet de classe, nous pouvons obtenir l'objet de package décrivant le package où se trouve la classe (la classe de package est définie dans java.lang). Nous pouvons également utiliser le nom du package pour obtenir l'objet de package en appelant la méthode statique GetPackage ou en appelant la méthode statique GetPackages (qui renvoie un tableau composé de tous les packages connus du système). La méthode GetName peut renvoyer le nom complet du package.
L'utilisation d'objets de package est complètement différente des autres types de réflexion, c'est-à-dire que nous ne pouvons pas créer ou manipuler des packages au moment de l'exécution. Nous pouvons utiliser des objets de package pour obtenir des informations sur des packages, tels que le but du package, qui a créé le package, la version du package, etc. Nous reporterons ces contenus jusqu'à ce que nous en discutions en détail plus tard.
Dénomination du package
Les noms de packages doivent éviter les conflits avec d'autres packages, donc choisir un nom à la fois significatif et unique est un aspect important de la conception des packages. Cependant, les programmeurs du monde entier développent des packages, et il n'y a aucun moyen de savoir qui a utilisé le nom du package, donc choisir le seul nom de package est un problème. Si nous déterminons qu'un package n'est utilisé que dans notre organisation, nous pouvons avoir un arbitre interne pour garantir qu'il n'y a pas de conflit de nom entre les projets.
Mais pour le monde entier, cette approche n'est pas pratique. Les identifiants de package sont tous des noms simples et une meilleure façon de s'assurer que le nom du package consiste à utiliser un nom de domaine Internet. Si l'entreprise dans laquelle nous travaillons est Magic.lnc et que le nom de domaine de l'entreprise est Magic C.com, alors la déclaration du package d'attribut devrait être:
package com.magic.attr;
Notez que les éléments constituants du nom de domaine ici sont organisés dans l'ordre inverse du nom de domaine conventionnel.
Si nous adoptons cet idiome, les noms de packages que nous utilisons ne seront en conflit avec personne d'autre que pour le conflit possible au sein de notre organisation. S'il existe en effet un conflit au sein de notre organisation (probablement une grande entreprise), nous pouvons utiliser des noms de domaine plus spécifiques pour être qualifiés. De nombreuses grandes entreprises ont des sous-domaines internes, comme l'Est et l'Europe, qui peuvent être utilisés pour qualifier davantage le nom du package:
Package Corn.magic.japan.attr;
L'utilisation de cette solution peut rendre le nom du package très long, mais il est relativement sûr. Les programmeurs utilisant cette technique ne choisiront pas le même nom de package, et les programmeurs qui n'utiliseront pas cette technique ne choisiront pas le nom que nous utilisons.
Contenu de package
Le contenu du package doit être soigneusement conçu pour qu'ils n'incluent que des classes et des interfaces pertinentes fonctionnelles. Les classes du package peuvent accéder librement aux membres non privés d'autres classes du package, et certaines classes peuvent même avoir des autorisations suffisantes pour accéder aux détails internes des autres classes. Afin d'éviter de telles classes des membres de la classe erronés, nous devons protéger les membres de la classe. Tout membre non déclaré comme privé est accessible par tous les autres types dans le même package, de sorte que toutes les classes non liées peuvent être plus susceptibles d'être plus coordonnées que prévu.
Les packages fournissent également un regroupement logique pour les programmeurs à la recherche d'interfaces et de classes utiles. Les packages composés de classes non pertinents rendent difficile pour les programmeurs de dire quelles interfaces et classes sont utiles, et le regroupement logique des classes peut aider les programmeurs à réutiliser le code car les programmeurs peuvent trouver ce dont ils ont besoin plus facilement grâce à un regroupement logique. Si le package ne contient que des ensembles de types liés et étroitement couplés, cela signifie que nous pouvons donner au type des noms plus intuitifs pour éviter les conflits de noms.
Les colis peuvent être imbriqués. Par exemple, Java.lang est un package imbriqué où le Lang Lang est imbriqué dans un package plus grand Java, tandis que le package J Ava contient également d'autres packages. La nidification fait que les packages associés forment un système de dénomination avec une structure hiérarchique.
Par exemple, pour créer un ensemble de packages pour les systèmes adaptatifs tels que les réseaux de neurones et les algorithmes génétiques, nous pouvons nommer des packages avec des noms séparés par DOT pour créer des packages imbriqués:
package adaptatif. neural net;
Le fichier source contenant l'instruction de déclaration ci-dessus est situé dans le package Adaptive.NuralNet, et le package Adaptive.Neralnet lui-même est un sous-package du package adaptatif. Le package adaptatif peut contenir certaines classes liées aux algorithmes adaptatifs généraux, tels que des classes de déclaration de problème de généralisation ou des classes de référence. Les packages qui sont dans une position plus profonde dans la hiérarchie (par exemple Adaptive.Neu-Ralnet ou Adaptive.Génétique) contiennent des classes liées à un type spécifique d'algorithme adaptatif.
La nidification des packages n'est qu'un outil pour organiser des packages connexes, et il ne fournit aucun droit d'accès spécial entre les packages.
Le code de classe dans le package Adaptive.Génétique ne peut pas accéder aux membres du package adaptatif ou adaptif.Neralnet qui ont des droits d'accès aux packages, et la portée du package ne s'applique qu'aux packages spécifiques. La nidification des packages peut regrouper les packages pertinents et aider les programmeurs à trouver la classe souhaitée au niveau logique plus pratique, mais au-delà, il n'apporte aucun autre avantage.
Notes de package
Le package peut également avoir des annotations. Mais le problème est que, comme les packages sont une structure organisationnelle sans entités de code source et qu'ils n'ont aucune définition réelle, ils ne peuvent pas être annotés comme des classes ou des méthodes, donc l'annotation du package ne peut être réalisée qu'en annotant l'instruction de déclaration du package dans le fichier source. Cependant, il ne peut y avoir qu'une seule déclaration de package dans chaque package qui peut avoir des annotations qui y agissent.
Alors, comment annotez-vous les packages? En fait, Java n'oblige pas les programmeurs à utiliser un moyen de gérer la règle "Instruction de package annotée unique". La manière recommandée consiste à créer un fichier nommé Package-i nfo.java dans le répertoire des packages, dans lequel seuls les instructions de package et les annotations du package sont stockées sans rien placer d'autre. Par exemple, le fichier Package Info.java pour le package ATTR ressemble à ceci:
@PackagesPec (Name Two "Astr Project", version = "1.0" @DevelopmentsIte ("att.project.org") @DevelopmentModel ("OpenSource") package att;Les packagesPEC, le site de développement et le développement OpmentModel sont utilisés pour modifier les types d'annotation. Bien sûr, ils ont des stratégies d'économie d'exécution. Le fichier package-fo.java doit être compilé avec d'autres fichiers source dans le package.
Nous vous recommandons de placer toutes les informations liées au package dans le fichier package-fo.java. Si vous faites cela, vous pouvez placer des commentaires de documents au début du fichier, afin que ces documents soient annotés comme documents de package.
Accès aux forfaits
Lorsque vous déclarez l'accessibilité des classes de haut niveau et des interfaces de niveau supérieur dans les packages, il existe deux options: l'accès à package (package) et l'accès public (public). Les classes ou les interfaces modifiées avec le public sont accessibles par code hors package, tandis que les types non décorés avec le public ont une portée du package: ils sont accessibles par d'autres codes dans le même package; Mais ils sont cachés pour les codes hors package, même dans les codes de sous-package. Lors de la déclaration des types, nous ne devons déclarer ces types que les autres programmeurs doivent utiliser en tant que public et masquer ces types qui appartiennent aux détails d'implémentation du package. Cette technologie nous offre une grande flexibilité, et comme les programmeurs ne s'appuient pas sur ces types de détails d'implémentation auxquels ils ne peuvent pas accéder, nous pouvons les modifier librement lorsque nous voulons modifier les détails de l'implémentation.
Les membres de la classe qui ne sont pas déclarés publics, protégés ou privés sont accessibles directement par un code à l'intérieur du package, mais sont cachés de l'extérieur du package. En d'autres termes, le modificateur d'accès par défaut est "package", à l'exception des membres de l'interface, et leur modificateur d'accès par défaut est "public".
Les champs ou méthodes qui ne sont pas déclarés privés dans un package sont accessibles par tous les autres code de ce package, de sorte que les classes du même package sont considérées comme "amicales" ou "de confiance". Cela nous permet de définir un cadre d'application qui combine le code prédéfini et le code d'espace réservé, où le code d'espace réservé est remplacé par une sous-classe de la classe Framework. Les codes prédéfinis peuvent utiliser les modificateurs d'accès des packages afin que d'autres codes collaboratifs dans le package puissent y accéder directement, mais pour les utilisateurs hors package, ces codes sont inaccessibles. Cependant, les sous-packages des packages où se trouvent ces codes ne sont pas fiables et vice versa. Par exemple, le code modifié avec le modificateur d'accès à package dans le package DIT ne peut pas être accessible par le code dans son package enfant Dit.dat, et vice versa.
Par conséquent, chaque type définit trois contrats différents:
.publi. Contrat: définit la fonction principale du type.
. Contrat protégé: définit les fonctions disponibles pour les sous-classes à des fins de spécialisation.
.Package Contrat: définit les fonctions qui peuvent être obtenues par un autre code dans le package pour réaliser une collaboration entre les types du package. Tous ces contrats nécessitent une attention particulière et une conception.
Méthode d'accessibilité et de couverture
Seules les méthodes accessibles dans les superclasses peuvent être écrasées dans les sous-classes. Si une méthode dans la superclasse ne peut pas être accessible, la méthode ne peut pas être remplacée dans la sous-classe même si la méthode de la sous-classe a le même nom que la méthode. Lorsqu'une méthode est appelée lors de l'exécution, le système considère son accessibilité et détermine ainsi la mise en œuvre de celui-ci.
L'exemple spécialement construit suivant s'explique plus clairement. Supposons que nous déclarons une classe de base abstraite dans le package P1:
Package P1; {Ab ab ab a abstract class abstractbase private void pri () {print ("stractBase.pri ()"):} void pac () {print ("stractBase.pac ()"); } protégée void pro () {print ("stractBase.pro ()"); } public void pub () {print ("stractBase.pub ()");} public final void show () pri (); Pac (); pro(); pub(); }}Dans cette classe, nous définissons 4 méthodes, chacune avec un modificateur d'accès différent, et le corps de la méthode ne s'identifie que. La méthode montre à son tour ces 4 méthodes sur l'objet actuel. Lors de l'application de cette méthode à différents objets de sous-classe, il peut expliquer quelle implémentation de ces méthodes est appelée.
Maintenant, nous définissons le Class Concretel, qui étend la classe AbstractBase, mais se trouve dans le package P2:
Package P2; Import p1.abstractbase classe publique CHASSE CONCRETEL étend AbstractBase {public void pri () {print ("Concretel.pri ()");} public void pac () {print ("concretel.pac ()");} public void pro () {print ("concretel.pro ()");} public Void public pub () {print ("Concretel.pub ()");}}Les 4 méthodes de la superclasse sont reclatées dans cette classe et leurs implémentations sont modifiées, qui rapportent qu'elles appartiennent à la classe Con-Cretel. Dans le même temps, leurs droits d'accès ont été transformés en public pour un autre code pour accéder. Exécuter le code suivant
New Concretel (). Show ():
La sortie suivante sera générée:
AbstractBase.pri () AbstractBase.Pac () Concretel.Pro () CONCRETEL.PUB ()
Étant donné que la méthode privée PRI ne peut pas être accessible par des sous-classes (ou d'autres classes), la méthode Show appelle toujours l'implémentation de la méthode PRI dans la classe AbstractBase. La méthode PAC avec les autorisations d'accès à package dans la classe AbstractBase ne peut pas être accessible par Concretel, de sorte que l'implémentation de la méthode PAC dans la classe Concretel ne peut pas remplacer la définition dans la classe AbstractBase, de sorte que la méthode Show appelle la méthode AbstractBase.pac. La méthode Pro et la méthode Pub sont toutes deux accessibles dans la classe Concretel et peuvent également être écrasées, de sorte que la méthode Show appelle la mise en œuvre de ces deux méthodes dans la classe Concretel.
Suivez notre classe Foot Signification Concrete2 pour étendre le Class Concretel, puis nous le mettons dans le même package P1 que la classe AbstractBase ':
Package P1; Import P2.Concretel public class public btete2 étend le concrète {public void pri () {print ("Concrete2.pri ()");} public void pac () {print ("Concrete2.pac ()");} public void pro () {print ("Concrete2.pro ()");} public void pub () {imprime }Étant donné que les méthodes de Concretel ont des droits d'accès public, ils sont accessibles dans Concrete2, et chaque méthode dans Concrete2 couvre ses méthodes correspondantes séparément. De plus, puisque Concrete2 et AbstractBase sont dans le même package, la méthode abstractBase.pac est également accessible dans Concrete2, et la méthode Concrete2.pac peut être remplacée. Appelez la méthode Show sur l'objet Concrete2, et le résultat d'impression est le suivant:
AbstractBase.pri () Concrete2.pac () Concrete2.pro () Concrete2.pub ()
Enfin, nous définissons la classe Concrete3 pour étendre la classe Concrete2 et la mettons dans le package P3:
package P3 Importer P1.Concrete2; classe publique Concrete3 étend le béton2 {public void pri () {print ("concret3.pri ()");} public void pac q {print ("Concrete3.pac ()");} public void pro () {print ("concret3.pro ()");}Appelez la méthode Show sur l'objet Concrete3, et le résultat d'impression est le suivant:
AbstractBase.pri () Concrete3.pac () Concrete3.pro () Concrete3.pub ()
Ici, la méthode Concrete3.pac semble remplacer la méthode inaccessible abstractbase.pac, mais en fait, la méthode Concrete3.pac remplace la méthode concrete2.pac, et la méthode Concrete2.pac remplace la méthode abstractbase.pac, donc la méthode concrete3.pac remplace indirectement la méthode abstractbase.pac. En redémarrant la méthode PAC dans la classe Concrete2 comme ayant des autorisations d'accès public, il peut être accessible et écrasé par toute sous-classe.
Package objets et spécifications
Les packages implémentent généralement certaines spécifications et proviennent généralement d'une organisation. Les objets de package sont différents des autres types de réflexion et ne peuvent pas être utilisés pour créer ou exploiter des packages, mais ne peuvent servir que de base de connaissances pour fournir des informations, qui fournit des informations sur les spécifications implémentées par le package (le titre, le fournisseur et le numéro de version) et les informations sur l'implémentation du package lui-même (le titre, le vendeur et le numéro de version du package). Bien que les packages proviennent généralement d'organisations individuelles, les spécifications qu'il met en œuvre (telles que les bibliothèques d'analyse statistique) peuvent être définies par d'autres organisations. Les programmes utilisant des packages peuvent avoir besoin de connaître la version de la spécification implémentée par le package, de sorte que les fonctions définies uniquement dans une certaine version peuvent être utilisées. De même, ces programmes peuvent également avoir besoin de savoir quelle version d'implémentation lui est fournie, principalement pour faire face aux défauts possibles dans différentes versions. Certaines des principales méthodes de la classe de packages permettent d'accéder à ces informations:
・ Public stri ng getName (): renvoie le nom du package.
.Public String GetSpecificationTitle P: Renvoie le titre de la spécification implémentée par le package. Si le titre est inconnu, retournez null,
.Public String getSpecificationVersion (): Renvoie une chaîne décrivant les informations de version de la spécification implémentée par le package. Si les informations de la version sont inconnues, retournez NULL,
.Public String GetSpecificationVendor Q: Renvoie le nom du fournisseur, qui possède et maintient les spécifications implémentées par le package. Si le fournisseur est inconnu, retournez null,
.Public String getIMPlerentationTitle (): Renvoie le titre de l'implémentation fournie par le package. Si le titre est inconnu, il renvoie Null, ・ public String getImplementationSion (): Renvoie une chaîne décrivant les informations de version de l'implémentation fournies par le package. Si les informations de la version sont inconnues, elle renvoie Null,
・ Public String getIMPlementationVendor (): Renvoie le nom de l'organisation (fournisseur) qui fournit la mise en œuvre. Si l'organisation est inconnue, retournez null,
Par exemple, si nous extraissons ces informations du package java.lang de notre système, nous obtiendrons les résultats suivants:
Titre de la spécification: API de la plate-forme Java Spécification Spécification Version: 1.4 Spécification Vendeur: Sun Microsystems, Inc. Titre de l'implémentation: Java Runtime Environment Implementation Version: 1.5.0_02 Implémentation Vendeur: Sun Microsystems, Inc.
Le numéro de version canonique se compose de nombres non négatifs séparés par des délimiteurs d'époque, tels que '' 2.0 '' ou '11 .0.12 '. Ce modèle nous permet d'appeler la méthode ISCompatible avec comparer le numéro de version qui suit ce modèle avec le numéro de version du package. Si le numéro de version du package est supérieur ou égal au numéro de version du successeur, la méthode renvoie true. Cette comparaison compare uniquement un numéro séparé par période à la fois. Si l'un de ces nombres est plus petit que la position correspondante dans le numéro de version passée, les deux versions sont incompatibles. Si l'un des numéros de version est plus long que l'autre, la partie manquante des numéros de version courte sera considérée comme zéro. Par exemple, si le numéro de version canonique du package est "1.4" et que nous le comparons avec "1.2", "1.3.1 '. Ou" .1.81., Alors True sera retourné; Mais par rapport à "1.4.2 '. ou" .5 ", alors False sera retourné. Cette conclusion est tirée car ce mécanisme de comparaison suppose que la version de spécification est compatible en arrière.
Il n'y a pas de format spécifié pour le numéro de version d'implémentation, car différentes organisations qui fournissent l'implémentation définiront différemment la version d'implémentation. La seule comparaison qui peut être faite entre les versions d'implémentation est de tester si la version est la même, où il n'y a pas d'hypothèse de compatibilité arriérée.
Le package peut être scellé, ce qui signifie que les classes ne peuvent plus être ajoutées au package. Les packages non scellés peuvent contenir des classes à partir de plusieurs emplacements différents dans le chemin de recherche de classe, tandis que le contenu du package scellé doit provenir du même emplacement - soit une archive spécifique, soit un emplacement spécifié par une URL. Il existe deux façons de déterminer si un paquet est scellé:
.Public Boolean Issesaled P: Retour Trueo si le colis est scellé
.Public Boolean ISSaled (URL URL): Retour True Si le package est scellé pour l'URL donnée, c'est-à-dire que les classes du package peuvent être chargées à partir de cette URL donnée. Si la classe du package ne peut pas être chargée à partir d'une URL donnée ou si le package n'est pas scellé, alors FAUX est renvoyé et que les informations de spécification et d'implémentation du package sont généralement fournies dans le cadre du fichier manifeste stocké avec le package - par exemple dans le cadre du fichier manifeste dans un archive Java (JAR), comme décrit dans la section 25.9.2, «Archive File Java.util.jar». Lorsqu'une classe dans un package est chargée, ces informations sont lues par la personne. Un Classloader peut définir dynamiquement un objet de package pour la classe qu'il souhaite charger:
.Pack Protected Package Denepackage (Nom de chaîne, String Spectitle, String Specversion, String SpecVendor, String Impltitle, String Implversion, String ImplVendor, URL Sealbase): Cette méthode renverra un objet de package avec le nom de package donné et la valeur de spécification et d'implémentation défini par le devis correspondant. Si la base de phase de paramètre est nulle, le package n'est pas scellé, sinon le package est scellé pour cette URL: l'objet de package de la classe doit être défini avant la définition de la classe et que le nom du package doit être unique dans le chargeur de classe. Si le nom du package est répété avec le nom existant, le travail 11EGA1ArgumentException sera lancé.
Nous pouvons appeler la méthode GetPackage de l'objet de classe de la classe donnée pour obtenir l'objet de package de cette classe. Nous pouvons également appeler le package statique.getPackage avec le nom de package donné pour obtenir l'objet de package, ou appeler le package statique.GetPackages, qui renverra le tableau de package composé de tous les packages actuellement connus dans le chargeur de classe. Les deux méthodes sont liées au chargeur de classe qui appelle leur code, car ces codes appellent les méthodes Get-Package ou GetPackages de leur chargeur de classe. Les méthodes de ces chargeurs de classe rechercheront un chargeur de classe spécifique et tous ses chargeurs de classe parent, et si aucun paramètre n'est fait pour le chargeur de classe actuel, le chargeur de classe système sera utilisé pour le moment. Notez que si le package est inconnu, la méthode Classloader retournera NULL car aucun type dans le package n'a été chargé pour le moment.