Wenn wir die GetPackage -Methode im Klassenobjekt aufrufen, können wir das Paketobjekt erhalten, das das Paket beschreibt, in dem sich die Klasse befindet (die Paketklasse ist in Java.lang definiert). Wir können den Paketnamen auch verwenden, um das Paketobjekt zu erhalten, indem wir die statische Methode getPackage oder die statische Methode getPackages aufrufen (die ein Array zurückgibt, das aus allen bekannten Paketen im System besteht). Die GetName -Methode kann den vollständigen Namen des Pakets zurückgeben.
Die Verwendung von Paketobjekten unterscheidet sich völlig von anderen Reflexionstypen, d. H. Wir können Pakete zur Laufzeit nicht erstellen oder manipulieren. Wir können Paketobjekte verwenden, um Informationen über Pakete zu erhalten, z. B. den Zweck des Pakets, das das Paket erstellt hat, die Version des Pakets usw. Wir werden diese Inhalte verschieben, bis wir sie später ausführlich besprechen.
Benennung des Pakets
Paketnamen sollten Konflikte mit anderen Paketen vermeiden. Die Auswahl eines Namens, der sowohl sinnvoll als auch eindeutig ist, ist ein wichtiger Aspekt des Paketdesigns. Programmierer auf der ganzen Welt entwickeln jedoch Pakete, und es gibt keine Möglichkeit zu wissen, wer den Namen des Pakets verwendet hat. Die Auswahl des einzigen Paketnamens ist also ein Problem. Wenn wir feststellen, dass ein Paket nur in unserer Organisation verwendet wird, können wir einen internen Schiedsrichter haben, um sicherzustellen, dass kein Name -Konflikt zwischen den Projekten besteht.
Aber für die ganze Welt ist dieser Ansatz nicht praktisch. Packungskennungen sind alle einfachen Namen und eine bessere Möglichkeit, um sicherzustellen, dass der Paketname darin besteht, einen Internet -Domain -Namen zu verwenden. Wenn das Unternehmen, in dem wir arbeiten, Magic.lnc ist und der Domainname des Unternehmens Magic C.com ist, sollte die Erklärung des Attributpakets lautet:
Paket com.magic.attr;
Beachten Sie, dass die Bestandteile der Domänennamen hier in umgekehrter Reihenfolge des herkömmlichen Domainnamens angeordnet sind.
Wenn wir diese Idiom übernehmen, werden die von uns verwendeten Paketnamen mit Ausnahme des möglichen Konflikts innerhalb unserer Organisation nicht im Widerspruch zu anderen stehen. Wenn es in unserer Organisation tatsächlich einen Konflikt gibt (wahrscheinlich ein großes Unternehmen), können wir spezifischere Domainnamen verwenden, um sich weiter zu qualifizieren. Viele große Unternehmen haben interne Subdomains wie Ost und Europa, die verwendet werden können, um den Namen des Pakets weiter zu qualifizieren:
Paket corn.magic.japan.attr;
Die Verwendung dieser Lösung kann den Paketnamen sehr lang machen, aber es ist relativ sicher. Programmierer, die diese Technik verwenden, wählen nicht denselben Paketnamen, und Programmierer, die diese Technik nicht verwenden, wählen nicht den von uns verwendeten Namen.
Paketinhalte
Der Inhalt des Pakets sollte sorgfältig so gestaltet werden, dass sie nur funktional relevante Klassen und Schnittstellen enthalten. Klassen im Paket können frei auf nicht private Mitglieder anderer Klassen im Paket zugreifen, und einige Klassen haben möglicherweise sogar über ausreichende Berechtigungen, um auf interne Details anderer Klassen zuzugreifen. Um solche Klassen von falsch operierenden Klassenmitgliedern zu vermeiden, müssen wir Klassenmitglieder schützen. Jedes Mitglied, das nicht als privat erklärt wird, kann von allen anderen Typen im selben Paket zugegriffen werden, sodass alle nicht verwandten Klassen eher koordiniert sind als wir erwarten würden.
Pakete bieten auch logische Gruppierung für Programmierer, die nach nützlichen Schnittstellen und Klassen suchen. Pakete, die aus irrelevanten Klassen bestehen, erschweren den Programmierern es schwierig zu sagen, welche Schnittstellen und Klassen nützlich sind, und die logische Gruppierung von Klassen kann den Programmierern helfen, Code wiederzuverwenden, da Programmierer, was sie durch logische Gruppierung leichter benötigen, einfacher finden können. Wenn das Paket nur verwandte, eng gekoppelte Typ -Sets enthält, bedeutet dies, dass wir dem Typ einige intuitivere Namen geben können, um Namenskonflikte zu vermeiden.
Pakete können verschachtelt werden. Zum Beispiel ist Java.lang ein verschachteltes Paket, in dem das Paket Lang in größerem Paket Java verschachtelt ist, während das Paket J AVA auch einige andere Pakete enthält. Durch Nisting bilden die zugehörigen Pakete ein Namenssystem mit hierarchischer Struktur.
Um beispielsweise eine Reihe von Paketen für adaptive Systeme wie neuronale Netzwerke und genetische Algorithmen zu erstellen, können wir Pakete mit dot-getrennten Namen benennen, um verschachtelte Pakete zu erstellen:
Paket adaptiv. neuronales Netz;
Die Quelldatei mit der oben genannten Deklarationsanweisung befindet sich im adaptiven.neuralNet -Paket, und das adaptive.neuralNet -Paket selbst ist ein Unterpackung des adaptiven Pakets. Das adaptive Paket kann einige Klassen enthalten, die sich auf allgemeine adaptive Algorithmen beziehen, wie z. Pakete, die sich in einer tieferen Position in der Hierarchie befinden (z. B. adaptiv.neu-ralnet oder adaptive.genetic), enthalten Klassen, die sich auf einen bestimmten Typ von adaptivem Algorithmus beziehen.
Die Verschachtelung von Paketen ist nur ein Werkzeug für die Organisation der zugehörigen Pakete und bietet keine speziellen Zugriffsrechte zwischen Paketen.
Der Klassencode im adaptiven Paket kann nicht auf die Mitglieder im adaptiven oder adaptiven.neuralnet -Paket zugreifen, das Paketzugriffsrechte verfügt, und der Paketumfang ist nur für bestimmte Pakete anwendbar. Die Verschachtelung von Paketen kann relevante Pakete gruppieren und Programmierern helfen, die gewünschte Klasse auf logischer Ebene bequemer zu finden, aber darüber hinaus bringt sie keine anderen Vorteile mit sich.
Paketnotizen
Das Paket kann auch Anmerkungen haben. Das Problem ist jedoch, dass Pakete, da Pakete eine Organisationsstruktur ohne Quellcode -Entitäten sind und keine tatsächliche Definition haben, nicht wie Klassen oder Methoden kommentiert werden können. Daher kann die Anweisung des Pakets nur durch Anmerkungen der Erklärung des Pakets in der Quelldatei erreicht werden. In jedem Paket kann es jedoch nur eine Paketerklärung geben, die Anmerkungen haben, die darauf reagieren.
Wie kommst du Pakete an? Tatsächlich zwingt Java die Programmierer nicht, mit der Regel "Einzelanträge für Paketanweisungen" zu befassen. Die empfohlene Möglichkeit besteht darin, eine Datei mit dem Namen Package-I nfo.java im Paketverzeichnis zu erstellen, in dem nur die Paketanweisungen und Anmerkungen des Pakets gespeichert werden, ohne etwas anderes zu platzieren. Beispielsweise sieht die Paket info.java -Datei für das ATT -Paket so aus:
@PackageSpec (Name zwei "Attr-Projekt", Version = "1.0" @DevelopmentSite ("attr.project.org") @DevelopmentModel ("Open-Source") Paket Attr;PackageSpec, Entwicklungs- und Entwicklungs -Opmentmodel werden verwendet, um Annotationstypen zu ändern. Natürlich haben sie Laufzeitsparstrategien. Paket-info.java-Datei sollte mit anderen Quelldateien im Paket kompiliert werden.
Wir empfehlen, alle paketbezogenen Informationen in die Paketinfo.java-Datei zu platzieren. Wenn Sie dies tun, können Sie zu Beginn der Datei Dokumentenkommentare platzieren, damit diese Dokumente als Paketdokumente kommentiert werden.
Paketzugriff
Bei der Erklärung der Barrierefreiheit von Klassen auf höchstem Niveau und Schnittstellen auf der Top-Ebene in Paketen gibt es zwei Optionen: Paketzugriff (Paket) und öffentlicher Zugang (öffentlich). Klassen oder Schnittstellen, die mit der Öffentlichkeit geändert wurden, können mit Out-of-Package-Code zugegriffen werden, während Typen, die nicht mit der Öffentlichkeit dekoriert sind, Paketumfang haben: Sie können durch andere Codes im selben Paket zugegriffen werden. Aber sie sind auch für Out-of-Package-Codes versteckt, auch in Subpackage-Codes. Bei der Erklärung von Typen sollten wir nur die Typen deklarieren, die andere Programmierer als öffentlich verwenden müssen, und die Typen verbergen, die zu den Implementierungsdetails des Pakets gehören. Diese Technologie bietet uns große Flexibilität, und da Programmierer nicht auf diese Art von Implementierungsdetails angewiesen sind, auf die sie nicht zugreifen können, können wir sie frei ändern, wenn wir die Implementierungsdetails ändern möchten.
Klassenmitglieder, die nicht als öffentlich, geschützt oder privat erklärt werden, können direkt mit jedem Code innerhalb des Pakets zugegriffen werden, sind jedoch von außerhalb des Pakets versteckt. Mit anderen Worten, der Standardzugangsmodifikator ist "Paket", mit Ausnahme der Mitglieder der Schnittstelle, und der Standard -Zugriffsmodifikator ist "öffentlich".
Auf Felder oder Methoden, die in einem Paket nicht privat erklärt werden, können von allen anderen Code in diesem Paket zugegriffen werden, sodass Klassen im selben Paket als "freundlich" oder "vertrauenswürdig" gelten. Auf diese Weise können wir ein Anwendungsrahmen definieren, das vordefinierten Code und Platzhaltercode kombiniert, wobei der Platzhaltercode durch eine Unterklasse der Framework -Klasse überschrieben wird. Vordefinierte Codes können Paketzugriffsmodifikatoren verwenden, damit andere Kooperationscodes im Paket direkt auf sie zugreifen können. Bei Nutzern außerhalb des Packens sind diese Codes jedoch nicht zugänglich. Die Unterpackungen der Pakete, in denen sich diese Codes befinden, sind jedoch nicht vertrauenswürdig und umgekehrt. Beispielsweise kann der mit dem Paketzugriffsmodifikator im Paket DIT geänderte Code vom Code in seinem untergeordneten Paket dit.dat nicht zugegriffen werden und umgekehrt.
Daher definiert jeder Typ drei verschiedene Verträge:
.publi. Vertrag: Definiert die Hauptfunktion des Typs.
. Vertragsgeschützter Vertrag: Definiert die Funktionen, die Unterklassen für Spezialisierungszwecke zur Verfügung stehen.
.Package -Vertrag: Definiert die Funktionen, die mit einem anderen Code im Paket erhalten werden können, um die Zusammenarbeit zwischen Typen im Paket zu erreichen. Alle diese Verträge erfordern sorgfältige Berücksichtigung und Gestaltung.
Barrierefreiheit und Deckmethode
In Unterklassen können nur Methoden überschrieben werden, die in Superklassen zugänglich sind. Wenn auf eine Methode in der Superklasse nicht zugegriffen werden kann, kann die Methode nicht in der Unterklasse überschrieben werden, selbst wenn die Methode in der Unterklasse denselben Namen wie die Methode hat. Wenn eine Methode zur Laufzeit aufgerufen wird, berücksichtigt das System seine Zugänglichkeit und bestimmt somit fest, welche Implementierung ausgeführt wird.
Das folgende speziell konstruierte Beispiel wird deutlicher erklärt. Angenommen, wir deklarieren eine abstrakte Basisklasse im P1-Paket:
Paket P1; {Ab ab abab public Abstract Class AbstractBase private void pri () {print ("stractbase.pri ()"):} void pac () {print ("stractBase.pac ()"); } protected void pro () {print ("stractBase.pro ()"); } public void pub () {print ("stractBase.pub ()");} öffentliche endgültige void show () pri (); pac (); pro (); Pub (); }}In dieser Klasse definieren wir 4 Methoden mit jeweils einen anderen Zugriffsmodifikator, und der Körper der Methode identifiziert sich nur. Die Methode zeigt diese 4 Methoden auf dem aktuellen Objekt nacheinander auf. Bei der Anwendung dieser Methode auf verschiedene Subklassenobjekte kann erläutert werden, welche Implementierung dieser Methoden aufgerufen wird.
Jetzt definieren wir den Klassenbeton, der die AbstractBase -Klasse erweitert, sich jedoch im P2 -Paket befindet:
Paket P2; Import P1.abstractBase Public Class Concretel erweitert AbstractBase {public void pri () {print ("concretel.Pri ()");} public void pac () {print ("concretel.pac ()"); pub () {print ("concretel.pub ()");}}Die 4 Methoden in der Superklasse werden in dieser Klasse neu eingebracht und ihre Implementierungen werden geändert, was berichtet, dass sie zur Betrügerklasse gehören. Gleichzeitig wurden ihre Zugriffsrechte in die Öffentlichkeit geändert, damit andere Code zugreifen können. Führen Sie den folgenden Code aus
New Concretel (). Show ():
Die folgende Ausgabe wird erzeugt:
AbstractBase.Pri () AbstractBase.pac () Concretel.Pro () Concretel.pub ()
Da die private Methode PRI nicht durch Unterklassen (oder andere Klassen) zugegriffen werden kann, ruft die Show -Methode immer die Implementierung der PRI -Methode in der AbstractBase -Klasse auf. Auf die PAC -Methode mit Paketzugriffsberechtigungen in der AbstractBase -Klasse kann nicht von Concretel zugegriffen werden, so Die Pro -Methode und die Pub -Methode sind in der Betonklasse sowohl zugänglich als auch überschrieben, sodass die Showmethode die Implementierung dieser beiden Methoden in der Betonklasse aufruft.
Folgen Sie unserem Fuß, der Klasse Concrete2 bedeutet, um den Klassenbeton zu erweitern, und dann setzen wir es in das gleiche Paket P1 wie die AbstractBase -Klasse ':
Paket P1; Import P2.Concretel Public Class Concrete2 erweitert Concretel {public void pri () {print ("concrete2.Pri ()");} public void pac () {print ("concrete2.pac ()");} public void pro () {print ("concrete2.Pro ();}; }Da Methoden in Concretel öffentliche Zugriffsrechte haben, können sie in Concrete2 zugegriffen werden, und auf jede Methode in Beton2 deckt seine entsprechenden Methoden getrennt ab. Da Concrete2 und AbstractBase im selben Paket sind, kann auch die Methode AbstractBase.pac in Concrete2 zugegriffen werden, und auf die Methode Concrete2.pac kann überschrieben werden. Rufen Sie die Show -Methode im Concrete2 -Objekt auf, und das Druckergebnis lautet wie folgt:
AbstractBase.Pri () Concrete2.pac () Concrete2.Pro () Concrete2.pub ()
Schließlich definieren wir die Klasse Concrete3, um die Klasse Concrete2 zu erweitern und sie in Paket P3 zu setzen:
Paket P3 Import P1.Concrete2; public class Concrete3 extends Concrete2{ public void pri(){print("Concrete3.pri()");} public void pac Q{print("Concrete3.pac()");} public void pro(){print("Concrete3.pro()");} public void pub(){print("Concrete3.pub()");} }Rufen Sie die Show -Methode im Concrete3 -Objekt auf, und das Druckergebnis lautet wie folgt:
AbstractBase.Pri () Concrete3.pac () Concrete3.Pro () Concrete3.pub ()
Hier ist Methode concrete3.pac so aus, als ob es die unzugängliche AbstractBase.pac -Methode überschreibt. Durch die Neuanklage der PAC -Methode in Klassenbeton2 als öffentliche Zugriffsberechtigungen kann sie von jeder Unterklasse zugegriffen und überschrieben werden.
Paketobjekte und Spezifikationen
Pakete implementieren normalerweise einige Spezifikationen und stammen normalerweise aus einer Organisation. Paketobjekte unterscheiden sich von anderen Reflexionstypen und können nicht zum Erstellen oder Betrieb von Paketen verwendet werden. Sie können jedoch nur als Wissensbasis für die Bereitstellung von Informationen dienen, die Informationen zu den vom Paket implementierten Spezifikationen (Titel, Lieferanten und Versionsnummer) und Informationen zur Implementierung des Pakets selbst (der Titel, der Anbieter und die Versionsnummer des Pakets) enthalten. Obwohl Pakete normalerweise von einzelnen Organisationen stammen, können die von ihnen implementierten Spezifikationen (z. B. Bibliotheken für statistische Analyse) von anderen Organisationen definiert werden. Programme, die Pakete verwenden, müssen möglicherweise die Version der vom Paket implementierten Spezifikation kennen, sodass Funktionen, die nur in einer bestimmten Version definiert sind, verwendet werden können. In ähnlicher Weise müssen diese Programme möglicherweise auch wissen, welche Implementierungsversion ihnen bereitgestellt wird, hauptsächlich, um mögliche Fehler in verschiedenen Versionen zu bewältigen. Einige der Hauptmethoden der Paketklasse ermöglichen den Zugriff auf diese Informationen:
・ Öffentliche Strium GetName (): Gibt den Namen des Pakets zurück.
.Public String getSpecificationTitle P: Gibt den Titel der vom Paket implementierten Spezifikation zurück. Wenn der Titel unbekannt ist, geben Sie NULL zurück,
.Public String getSpecificationVersion (): Gibt einen Zeichenfolge zurück, in dem die Versionsinformationen der vom Paket implementierten Spezifikation beschrieben werden. Wenn die Versionsinformationen unbekannt sind, geben Sie NULL zurück,
.Public String getSpecificationVendor F: Gibt den Namen des Lieferanten zurück, der die vom Paket implementierten Spezifikationen besitzt und verwaltet. Wenn der Lieferant unbekannt ist, geben Sie NULL zurück,
.public String getImplerentationTitle (): Gibt den Titel der durch das Paket bereitgestellten Implementierung zurück. Wenn der Titel unbekannt ist, gibt er NULL zurück, ・ öffentliche String GetImplementationVersion (): Gibt eine Zeichenfolge zurück, in der die Versionsinformationen der durch das Paket bereitgestellten Implementierung beschrieben werden. Wenn die Versionsinformationen unbekannt sind, gibt sie NULL zurück.
・ Öffentliche String GetImplementationVendor (): Gibt den Namen der Organisation (Anbieter) zurück, die die Implementierung anbietet. Wenn die Organisation unbekannt ist, kehren Sie NULL zurück,
Wenn wir diese Informationen beispielsweise aus dem Java.lang -Paket in unserem System extrahieren, erhalten wir die folgenden Ergebnisse:
Spezifikationstitel: Java -Plattform -API -Spezifikation Spezifikation Version: 1.4 Spezifikationsanbieter: Sun Microsystems, Inc. Implementierung Titel: Java Runtime Environment Implementierung Version: 1.5.0_02 Implementierungsanbieter: Sun Microsystems, Inc.
Die kanonische Versionsnummer besteht aus nicht negativen Zahlen, die durch Periodengrenzwerte wie "2.0" oder '11 .0.12 "getrennt sind. Mit diesem Muster können wir die Methode iscompatible mit der Methode aufrufen, um die Versionsnummer zu vergleichen, die diesem Muster mit der Versionsnummer des Pakets folgt. Wenn die Versionsnummer des Pakets größer oder gleich der Versionsnummer des Nachfolgers ist, gibt die Methode true zurück. Dieser Vergleich vergleicht nur eine period getrennte Zahl gleichzeitig. Wenn eine dieser Zahlen kleiner als die entsprechende Position in der übergebenen Versionsnummer ist, sind die beiden Versionen nicht kompatibel. Wenn eine der Versionsnummern länger als der andere ist, wird der fehlende Teil in den Kurzversionsnummern als Null angesehen. Wenn beispielsweise die kanonische Versionsnummer des Pakets "1.4" ist und wir es mit "1.2", "1.3.1 'oder" .1.81. Vergleiche, wird True zurückgegeben. Im Vergleich zu "1.4.2 'oder" .5 "wird jedoch falsch zurückgegeben. Diese Schlussfolgerung wird gezogen, da dieser Vergleichsmechanismus davon ausgeht, dass die Spezifikationsversion rückwärts kompatibel ist.
Es gibt kein bestimmtes Format für die Implementierungsversionsnummer, da verschiedene Organisationen, die die Implementierung anbieten, die Implementierungsversion unterschiedlich definieren. Der einzige Vergleich, der zwischen Implementierungsversionen durchgeführt werden kann, besteht darin, zu testen, ob die Version gleich ist, wenn keine Annahme einer Rückwärtskompatibilität besteht.
Das Paket kann versiegelt werden, was bedeutet, dass Klassen nicht mehr zum Paket hinzugefügt werden können. Unversiegelte Pakete können Klassen von mehreren verschiedenen Standorten im Klassensuchpfad enthalten, während der Inhalt des versiegelten Pakets vom selben Ort stammen muss - entweder ein bestimmtes Archiv oder ein von einer URL angegebener Ort. Es gibt zwei Möglichkeiten, um festzustellen, ob ein Paket versiegelt ist:
.Public Boolean idealed p: Return trueo Wenn das Paket versiegelt ist
.Public boolean issealed (URL -URL): Rückgabe true Wenn das Paket für die angegebene URL versiegelt ist, können die Klassen im Paket von dieser gegebenen URL geladen werden. Wenn die Klasse im Paket nicht aus einer bestimmten URL geladen werden kann oder das Paket nicht versiegelt ist, wird Falsch zurückgegeben, und die Spezifikation und Implementierungsinformationen des Pakets werden normalerweise als Teil der mit dem Paket gespeicherten Manifestdatei bereitgestellt, z. Wenn eine Klasse in einem Paket geladen wird, werden diese Informationen von der Person gelesen. Ein Klassenloader kann ein Paketobjekt für die Klasse, die er laden möchte, dynamisch definieren:
.Paketes Paket DenePackage (String -Name, String -Spectitle, String -Specversion, String -Specvendor, String -Titeltitel, String -Verformung, String -Implvendor, URL -Sealbase): Diese Methode gibt ein Paketobjekt mit dem angegebenen Paketnamen und Spezifikations- und Implementierungswert zurück, das von der entsprechenden Quote festgelegt wurde. Wenn die Parameter Sealbase null ist, ist das Paket nicht versiegelt, andernfalls ist das Paket für diese URL versiegelt: Das Paketobjekt der Klasse muss vor der Definition der Klasse definiert werden und der Paketname muss im Klassenlader eindeutig sein. Wenn der Paketname mit dem vorhandenen Namen wiederholt wird, wird die Arbeit 11EGA1ArgumentException geworfen.
Wir können die Getpackage -Methode des Klassenobjekts der angegebenen Klasse aufrufen, um das Paketobjekt dieser Klasse zu erhalten. Wir können auch das statische Paket anrufen. Beide Methoden beziehen sich auf den Klassenlader, der ihren Code aufruft, da diese Codes die Get-Package- oder Getpackages-Methoden ihres Klassenladers aufrufen. Diese Methoden der Klassenlader suchen nach einem bestimmten Klassenlader und allen seinen übergeordneten Klassenladern. Wenn für den aktuellen Klassenlader keine Einstellungen vorgenommen werden, wird der Systemklassenlader zu diesem Zeitpunkt verwendet. Beachten Sie, dass die Klassenladermethode, wenn das Paket unbekannt ist, NULL zurückgibt, da zu diesem Zeitpunkt kein Typ im Paket geladen wurde.