Si llamamos al método GetPackage en el objeto de clase, podemos obtener el objeto del paquete que describe el paquete donde se encuentra la clase (la clase de paquete se define en java.lang). También podemos usar el nombre del paquete para obtener el objeto de paquete llamando al método estático getPackage o llamando al método estático getPackages (que devuelve una matriz compuesta por todos los paquetes conocidos en el sistema). El método GetName puede devolver el nombre completo del paquete.
El uso de objetos de paquete es completamente diferente de otros tipos de reflexión, es decir, no podemos crear ni manipular paquetes en tiempo de ejecución. Podemos usar objetos de paquete para obtener información sobre paquetes, como el propósito del paquete, quién creó el paquete, la versión del paquete, etc. Postpararemos estos contenidos hasta que los discutiremos en detalle más adelante.
Nombramiento del paquete
Los nombres de los paquetes deben evitar conflictos con otros paquetes, por lo que elegir un nombre que sea significativo y único es un aspecto importante del diseño de paquetes. Sin embargo, los programadores de todo el mundo están desarrollando paquetes, y no hay forma de saber quién usó qué nombre del paquete, por lo que elegir el único nombre del paquete es un problema. Si determinamos que un paquete solo se usa dentro de nuestra organización, podemos tener un árbitro interno para garantizar que no haya conflicto de nombre entre los proyectos.
Pero para todo el mundo, este enfoque no es práctico. Los identificadores de paquetes son todos nombres simples y una mejor manera de garantizar que el nombre del paquete sea usar un nombre de dominio de Internet. Si la empresa en la que estamos trabajando es Magic.lnc y el nombre de dominio de la compañía es Magic C.com, entonces la declaración del paquete de atributos debería ser:
paquete com.magic.attr;
Tenga en cuenta que los elementos constituyentes del nombre de dominio aquí están organizados en orden inverso del nombre de dominio convencional.
Si adoptamos este idioma, los nombres de los paquetes que usamos no entrarán en conflicto con los de nadie más, excepto por el posible conflicto dentro de nuestra organización. Si de hecho hay un conflicto dentro de nuestra organización (probablemente una gran empresa), entonces podemos usar nombres de dominio más específicos para calificar aún más. Muchas grandes empresas tienen subdominios internos, como East y Europa, que pueden usarse para calificar aún más el nombre del paquete:
paquete de maíz.magic.japan.attr;
El uso de esta solución puede hacer que el nombre del paquete sea muy largo, pero es relativamente seguro. Los programadores que usan esta técnica no elegirán el mismo nombre del paquete, y los programadores que no usan esta técnica no elegirán el nombre que usamos.
Contenido de paquete
El contenido del paquete debe diseñarse cuidadosamente para que solo incluyan clases e interfaces funcionalmente relevantes. Las clases en el paquete pueden acceder libremente a los miembros no privados de otras clases en el paquete, y algunas clases pueden incluso tener permisos suficientes para acceder a los detalles internos de otras clases. Para evitar tales clases de los miembros de la clase gestros, necesitamos proteger a los miembros de la clase. Cualquier miembro no declarado como privado puede ser accedido por todos los demás tipos en el mismo paquete, por lo que cualquiera de las clases no relacionadas puede ser más coordinada de lo que esperamos.
Los paquetes también proporcionan agrupación lógica para programadores que buscan interfaces y clases útiles. Los paquetes compuestos por clases irrelevantes dificultan que los programadores dan cuenta qué interfaces y clases son útiles, y la agrupación lógica de las clases puede ayudar a los programadores a reutilizar el código porque los programadores pueden encontrar lo que necesitan más fácilmente a través de la agrupación lógica. Si el paquete solo contiene conjuntos de tipos estrictamente acoplados relacionados, significa que podemos darle al tipo algunos nombres más intuitivos para evitar conflictos de nombres.
Los paquetes pueden estar anidados. Por ejemplo, Java.lang es un paquete anidado donde el paquete Lang está anidado en el paquete más grande Java, mientras que el paquete J AVA también contiene algunos otros paquetes. La anidación hace que los paquetes relacionados formen un sistema de nombres con estructura jerárquica.
Por ejemplo, para crear un conjunto de paquetes para sistemas adaptativos como redes neuronales y algoritmos genéticos, podemos nombrar paquetes con nombres separados por puntos para crear paquetes anidados:
paquete adaptativo. red neuronal;
El archivo fuente que contiene la declaración de declaración anterior se encuentra en el paquete Adaptive.neuralnet, y el paquete Adaptive.neuralnet en sí es un subpackage del paquete adaptativo. El paquete adaptativo puede contener algunas clases relacionadas con algoritmos adaptativos generales, como clases de declaración de problemas de generalización o clases de referencia. Los paquetes que están en una posición más profunda en la jerarquía (por ejemplo, adaptativa.neu-ralnet o adaptive.genetic) contienen clases relacionadas con un tipo específico de algoritmo adaptativo.
La anidación de los paquetes es solo una herramienta para organizar paquetes relacionados, y no proporciona ningún derecho de acceso especial entre paquetes.
El código de clase en el paquete Adaptive.Genetic no puede acceder a los miembros en el paquete adaptativo o adaptativo.neuralnet que tiene derechos de acceso al paquete, y el alcance del paquete solo se aplica a paquetes específicos. La anidación de los paquetes puede agrupar paquetes relevantes y ayudar a los programadores a encontrar la clase deseada en el nivel lógico de manera más conveniente, pero más allá de eso, no trae ningún otro beneficio.
Notas de paquete
El paquete también puede tener anotaciones. Pero el problema es que, dado que los paquetes son una estructura organizacional sin entidades del código fuente y no tienen una definición real, no pueden anotarse como clases o métodos, por lo que la anotación del paquete solo se puede lograr anotando la declaración de declaración del paquete en el archivo fuente. Sin embargo, solo puede haber una declaración de paquete en cada paquete que puede tener anotaciones que actúan en consecuencia.
Entonces, ¿cómo se anotan los paquetes? De hecho, Java no obliga a los programadores a usar alguna forma de lidiar con la regla de "Declaración de paquete anotado único". La forma recomendada es crear un archivo llamado paquete-i nfo.java en el directorio de paquetes, en el que solo las declaraciones del paquete y las anotaciones del paquete se almacenan sin colocar nada más. Por ejemplo, el archivo del paquete Info.java para el paquete ATTT se ve así:
@PackagesPec (nombre dos "Proyecto ATTR", versión = "1.0" @develoveltmentsite ("attr.project.org") @develovelopmentModel ("abre-sale") paquete attr;PACKAGSPEC, Desarrollo y OpmentModel de desarrollo se utilizan para modificar los tipos de anotación. Por supuesto, tienen estrategias de ahorro de tiempo de ejecución. paquete-Info.java El archivo debe compilarse con otros archivos de origen en el paquete.
Recomendamos colocar toda la información relacionada con el paquete en el archivo Package-Info.java. Si hace esto, puede colocar comentarios de documentos al comienzo del archivo, para que estos documentos se anoten como documentos de paquete.
Acceso al paquete
Al declarar la accesibilidad de las clases de nivel superior y las interfaces de nivel superior en los paquetes, hay dos opciones: acceso al paquete (paquete) y acceso público (público). Se puede acceder a las clases o interfaces modificadas con público mediante un código fuera de paquete, mientras que los tipos no decorados con público tienen alcance del paquete: se puede acceder a ellos por otros códigos en el mismo paquete; Pero están ocultos para códigos fuera de paquete, incluso en códigos de subpackage. Al declarar tipos, solo debemos declarar aquellos tipos que otros programadores deben usar como público y ocultar aquellos tipos que pertenecen a los detalles de implementación del paquete. Esta tecnología nos proporciona una gran flexibilidad, y dado que los programadores no confían en este tipo de detalles de implementación a los que no pueden acceder, podemos cambiarlos libremente cuando queremos cambiar los detalles de implementación.
Los miembros de la clase que no se declaran como públicos, protegidos o privados pueden acceder directamente a cualquier código dentro del paquete, pero que están ocultos desde fuera del paquete. En otras palabras, el modificador de acceso predeterminado es el "paquete", con la excepción de los miembros de la interfaz, y su modificador de acceso predeterminado es "público".
Los campos o métodos que no se declaran privados dentro de un paquete pueden acceder a todos los demás código en ese paquete, por lo que las clases en el mismo paquete se consideran "amigables" o "confiables". Esto nos permite definir un marco de aplicación que combina código predefinido y código de marcador de posición, donde el código del marcador de posición se anula por una subclase de la clase Framework. Los códigos predefinidos pueden usar modificadores de acceso al paquete para que otros códigos de colaboración dentro del paquete puedan acceder directamente a ellos, pero para los usuarios fuera de paquete, estos códigos son inaccesibles. Sin embargo, los subpackages de los paquetes donde se encuentran estos códigos no son confiables y viceversa. Por ejemplo, el código modificado con el modificador de acceso al paquete en el paquete DIT no se puede acceder por el código en su paquete infantil dit.dat, y viceversa.
Por lo tanto, cada tipo define tres contratos diferentes:
.publi. Contrato: Define la función principal del tipo.
. Contrato protegido: Define las funciones disponibles para las subclases para fines de especialización.
. Todos estos contratos requieren una cuidadosa consideración y diseño.
Accesibilidad y método de cobertura
Solo los métodos accesibles en las superclase se pueden sobrescribir en subclases. Si no se puede acceder a un método en la superclase, el método no se puede anular en la subclase incluso si el método en la subclase tiene el mismo nombre que el método. Cuando se llama a un método en tiempo de ejecución, el sistema considera su accesibilidad y, por lo tanto, determina qué implementación se está ejecutando.
El siguiente ejemplo especialmente construido se explica más claramente. Supongamos que declaramos una clase de base abstracta en el paquete P1:
Paquete P1; {Ab abab abab clase abstract abstractbase private void pri () {print ("stractbase.pri ()"):} void pac () {print ("stractbase.pac ()"); } protegido void pro () {print ("stractbase.pro ()"); } public void pub () {print ("stractbase.pub ()");} public final void show () pri (); pac (); pro(); pub(); }}En esta clase, definimos 4 métodos, cada uno con un modificador de acceso diferente, y el cuerpo del método solo se identifica. El método muestra estos 4 métodos en el objeto actual a su vez. Al aplicar este método a diferentes objetos de subclase, puede explicar qué implementación de estos métodos se llama.
Ahora, definimos la clase de concretel, que extiende la clase de base de abstracto, pero se encuentra en el paquete P2:
Paquete P2; import p1.Abstractbase public class Concretel extiende AbstractBase {public void pri () {print ("Concretel.pri ()");} public void pac () {print ("concretel.pac ()");} public void pro () {print ("Concretel.pro ()");} public void pub () {print ("Concretel.pub ()");}}Los 4 métodos en la superclase se redeclaron en esta clase y sus implementaciones se cambian, lo que informa que pertenecen a la clase Con-Cretel. Al mismo tiempo, sus derechos de acceso se han cambiado a público para que otro código acceda. Ejecutar el siguiente código
nuevo concretel (). show ():
Se generará la siguiente salida:
AbstractBase.pri () AbstractBase.pac () Concretel.pro () Concretel.pub ()
Debido a que no se puede acceder al método privado PRI mediante subclases (u otras clases), el método de exposición siempre llama a la implementación del método PRI en la clase de base Abstract. No se puede acceder al método PAC con permisos de acceso al paquete en la clase Abstract Base por concretel, por lo que la implementación del método PAC en la clase de concretel no puede anular la definición en la clase AbstractBase, por lo que el método de exposición llama al método abstractSbase.pac. El método Pro y el método PUB son accesibles en la clase de concretel y también se pueden sobrescribir, por lo que el método de exposición llama a la implementación de estos dos métodos en la clase de concretel.
Siga nuestra clase de significado de pie concrete2 para extender el concretel de clase, y luego lo colocamos en el mismo paquete P1 que la clase de base de resúmenes ':
Paquete P1; import p2.Concretel public class Concrete2 extiende Concretel {public void pri () {print ("concrete2.pri ()");} public void pac () {print ("concrete2.pac ()");} public void pro () {print ("Concrete2.pro ()");} Public Void Void Void Void Pub () {print ("" ConcRete ("); }Debido a que los métodos en el concretel tienen derechos de acceso público, se puede acceder en concreto2, y cada método en concrete2 cubre sus métodos correspondientes por separado. Además, dado que Concrete2 y AbstractBase están en el mismo paquete, también se puede acceder al método AbstractBase.pac en concrete2, y el método concrete2.pac se puede anular. Llame al método de programa en el objeto Concrete2, y el resultado de impresión es el siguiente:
AbstractBase.pri () concrete2.pac () concrete2.pro () concrete2.pub ()
Finalmente, definimos la clase Concrete3 para extender la clase Concrete2 y lo colocamos en el paquete P3:
Paquete P3 Importación P1.Concrete2; public class Concrete3 extiende 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 ()");Llame al método de programa en el objeto Concrete3, y el resultado de impresión es el siguiente:
AbstractBase.pri () Concrete3.pac () Concrete3.pro () Concrete3.pub ()
Aquí el método concrete3.pac parece que anula el método inaccesible abstractBase.pac, pero de hecho, el método concrete3.pac anula el método concrete2.pac, y el método concrete2.pac anula el método abstractBase.pac, SO método.pac anula indirectamente el método abstractBase.pac. Al redecar el método PAC en clase Concrete2 como que tiene permisos de acceso público, cualquier subclase puede acceder y sobrescribirse.
Paquete de objetos y especificaciones
Los paquetes generalmente implementan algunas especificaciones, y generalmente son de una organización. Los objetos de paquete son diferentes de otros tipos de reflexión y no se pueden usar para crear u operar paquetes, pero solo pueden servir como una base de conocimiento para proporcionar información, que proporciona información sobre las especificaciones implementadas por el paquete (el título, el proveedor y el número de versión) e información sobre la implementación del paquete en sí (el título, el proveedor y el número de versión del paquete). Aunque los paquetes generalmente provienen de organizaciones individuales, las especificaciones que implementa (como las bibliotecas de análisis estadístico) pueden ser definidas por otras organizaciones. Los programas que usan paquetes pueden necesitar conocer la versión de la especificación implementada por el paquete, de modo que las funciones definidas solo en una determinada versión se puedan utilizar. Del mismo modo, estos programas también pueden necesitar saber qué versión de implementación se le proporciona, principalmente para tratar posibles defectos en diferentes versiones. Algunos de los principales métodos de la clase de paquete permiten el acceso a esta información:
・ Public Stri ng getName (): Devuelve el nombre del paquete.
.Public String GetSpecificationTitle P: Devuelve el título de la especificación implementada por el paquete. Si el título es desconocido, regresa nulo,
.Public String getSpecificationVersion (): Devuelve una cadena que describe la información de la versión de la especificación implementada por el paquete. Si la información de la versión es desconocida, devuelva nulo,
.Public String GetSpecificationVendor P: Devuelve el nombre del proveedor, que posee y mantiene las especificaciones implementadas por el paquete. Si el proveedor es desconocido, regresa nulo,
.Public String getImplerentationTitle (): Devuelve el título de la implementación proporcionada por el paquete. Si el título se desconoce, devuelve nulo, ・ public String getImplementationVersion (): Devuelve una cadena que describe la información de la versión de la implementación proporcionada por el paquete. Si la información de la versión es desconocida, devuelve nulo,
・ Public String getImplementationVendor (): Devuelve el nombre de la organización (proveedor) que proporciona la implementación. Si la organización es desconocida, regresa nulo,
Por ejemplo, si extraemos esta información del paquete java.lang en nuestro sistema, obtendremos los siguientes resultados:
Título de la especificación: Java Platform API Especificación de especificación Versión: 1.4 Vendor de especificaciones: Sun Microsystems, Inc. Título de implementación: Java Runtime Entorno Implementación Versión: 1.5.0_02 Proveedor de implementación: Sun Microsystems, Inc.
El número de versión canónica consiste en números no negativos separados por delimitadores de época, como "2.0" o '11 .0.12 '. Este patrón nos permite llamar al método ISCompatibleWith para comparar el número de versión que sigue este patrón con el número de versión del paquete. Si el número de versión del paquete es mayor o igual al número de versión del sucesor, entonces el método devuelve verdadero. Esta comparación solo compara un número separado por el período a la vez. Si alguno de estos números es más pequeño que la posición correspondiente en el número de versión pasada, entonces las dos versiones son incompatibles. Si uno de los números de versión es más largo que el otro, la parte faltante en los números de versión corta se considerará cero. Por ejemplo, si el número de versión canónica del paquete es "1.4" y lo comparamos con "1.2", "1.3.1 '. O" .1.81., Entonces verdadero se devolverá; pero si se compara con "1.4.2 '. o" .5 ", entonces se devolverá False. Esta conclusión se extrae porque este mecanismo de comparación supone que la versión de especificación es compatible con retroceso.
No hay formato especificado para el número de versión de implementación, porque diferentes organizaciones que proporcionan la implementación definirán la versión de implementación de manera diferente. La única comparación que se puede hacer entre las versiones de implementación es probar si la versión es la misma, donde no hay una suposición de compatibilidad con atraso.
El paquete se puede sellar, lo que significa que las clases ya no se pueden agregar al paquete. Los paquetes no sellados pueden contener clases de múltiples ubicaciones diferentes en la ruta de búsqueda de clases, mientras que el contenido del paquete sellado debe provenir de la misma ubicación, ya sea un archivo específico o una ubicación especificada por una URL. Hay dos formas de determinar si un paquete está sellado:
.Public boolean issealed p: return trueO si el paquete está sellado
.Public boolean issealed (URL URL): devuelva verdadero si el paquete está sellado para la URL dada, es decir, las clases en el paquete se pueden cargar a partir de esta URL dada. Si la clase en el paquete no se puede cargar a partir de una URL dada, o el paquete no está sellado, entonces se devuelve False, y la información de especificación e implementación del paquete generalmente se proporciona como parte del archivo manifiesto almacenado con el paquete, por ejemplo, como parte del archivo manifiesto en un archivo Java (JAR), como se describe en la sección 25.9.2, "Archivo Java.uTil.Jar". Cuando se carga una clase en un paquete, la persona lee esta información. Un cargador de clases puede definir dinámicamente un objeto de paquete para la clase que desea cargar:
.protected Package DenePackage (nombre de cadena, String Spectitle, String Specversion, String SpecVendor, String Implititle, String Implersion, String ImplVendor, URL SealBase): este método devolverá un objeto de paquete con el nombre y la especificación y el valor de implementación de la implementación establecido por la cita correspondiente. Si el parámetro SealBase es nulo, entonces el paquete no está sellado, de lo contrario el paquete está sellado para esta URL: el objeto del paquete de la clase debe definirse antes de definir la clase, y el nombre del paquete debe ser único en el cargador de clase. Si el nombre del paquete se repite con el nombre existente, se lanzará el trabajo 11ega1argumentException.
Podemos llamar al método GetPackage del objeto de clase de la clase dada para obtener el objeto de paquete de esta clase. También podemos llamar al paquete estático. GetPackage con el nombre del paquete dado para obtener el objeto del paquete, o llamar al paquete estático.getPackages, que devolverá la matriz de paquetes compuesta por todos los paquetes que se conocen actualmente en el cargador de clase. Ambos métodos están relacionados con el cargador de clases que llama a su código, porque estos códigos llamarán a los métodos Get-Package o GetPackages de su cargador de clase. Los métodos de estos cargadores de clase buscarán un cargador de clase específico y todos sus cargadores de clase padre, y si no se realizan configuraciones para el cargador de clase actual, el cargador de clase del sistema se utilizará en este momento. Tenga en cuenta que si se desconoce el paquete, el método de carnero de clases devolverá nulo porque no se ha cargado ningún tipo en el paquete en este momento.