Se chamarmos o método getPackage no objeto de classe, podemos obter o objeto de pacote descrevendo o pacote em que a classe está localizada (a classe do pacote é definida em java.lang). Também podemos usar o nome do pacote para obter o objeto do pacote chamando o método estático getPackage ou chamando o método estático getPackages (que retorna uma matriz composta por todos os pacotes conhecidos no sistema). O método getName pode retornar o nome completo do pacote.
O uso de objetos de pacote é completamente diferente de outros tipos de reflexão, ou seja, não podemos criar ou manipular pacotes em tempo de execução. Podemos usar objetos de pacote para obter informações sobre pacotes, como o objetivo do pacote, que criou o pacote, a versão do pacote etc. Publicaremos esses conteúdos até que os discutiremos em detalhes posteriormente.
Nomeação do pacote
Os nomes dos pacotes devem evitar conflitos com outros pacotes, portanto, escolher um nome significativo e único é um aspecto importante do design de pacotes. No entanto, programadores em todo o mundo estão desenvolvendo pacotes, e não há como saber quem usou qual nome de pacote, portanto, escolher o único nome do pacote é um problema. Se determinarmos que um pacote é usado apenas em nossa organização, podemos ter um árbitro interno para garantir que não haja conflitos de nome entre projetos.
Mas para o mundo inteiro, essa abordagem não é prática. Os identificadores de pacotes são todos nomes simples e uma maneira melhor de garantir que o nome do pacote seja usar um nome de domínio da Internet. Se a empresa em que estamos trabalhando é Magic.LNC e o nome de domínio da empresa é Magic C.com, a declaração do pacote de atributos deve ser:
pacote com.magic.attr;
Observe que os elementos constituintes do nome de domínio aqui são organizados na ordem inversa do nome de domínio convencional.
Se adotarmos esse idioma, os nomes de pacotes que usamos não entrarão em conflito com a de mais ninguém, exceto o possível conflito em nossa organização. Se houver de fato um conflito em nossa organização (provavelmente uma grande empresa), podemos usar nomes de domínio mais específicos para se qualificarem ainda mais. Muitas grandes empresas têm subdomínios internos, como o Oriente e a Europa, que podem ser usados para qualificar ainda mais o nome do pacote:
pacote milho.magic.japan.attr;
O uso dessa solução pode tornar o nome do pacote muito longo, mas é relativamente seguro. Os programadores que usam essa técnica não escolherão o mesmo nome do pacote, e os programadores que não usam essa técnica não escolherão o nome que usamos.
Conteúdo do pacote
O conteúdo do pacote deve ser cuidadosamente projetado para que eles incluam apenas classes e interfaces funcionalmente relevantes. As aulas no pacote podem acessar livremente membros não privados de outras classes no pacote, e algumas classes podem até ter permissões suficientes para acessar detalhes internos de outras classes. Para evitar essas classes de misopelar os alunos, precisamos proteger os alunos da classe. Qualquer membro não declarado como privado pode ser acessado por todos os outros tipos no mesmo pacote; portanto, qualquer aula não relacionada pode ter mais probabilidade de ser mais coordenada do que esperávamos.
Os pacotes também fornecem agrupamento lógico para programadores que procuram interfaces e classes úteis. Os pacotes compostos por classes irrelevantes dificultam os programadores de que interfaces e classes são úteis, e o agrupamento lógico de classes pode ajudar os programadores a reutilizar o código porque os programadores podem encontrar o que precisam mais facilmente através do agrupamento lógico. Se o pacote contiver apenas conjuntos de tipos relacionados e bem acoplados, significa que podemos dar ao tipo alguns nomes mais intuitivos para evitar conflitos de nome.
Os pacotes podem ser aninhados. Por exemplo, Java.lang é um pacote aninhado em que o pacote Lang é aninhado em um pacote maior, enquanto o pacote J Ava também contém alguns outros pacotes. O ninho faz com que os pacotes relacionados formem um sistema de nomenclatura com estrutura hierárquica.
Por exemplo, para criar um conjunto de pacotes para sistemas adaptativos, como redes neurais e algoritmos genéticos, podemos nomear pacotes com nomes separados por pontos para criar pacotes aninhados:
pacote adaptativo. rede neural;
O arquivo de origem que contém a declaração de declaração acima está localizado no pacote Adaptive.NururalNet, e o pacote Adaptive.NururalNet em si é uma subpackagem do pacote adaptativo. O pacote adaptativo pode conter algumas classes relacionadas a algoritmos adaptativos gerais, como classes de declaração de problemas de generalização ou classes de referência. Os pacotes que estão em uma posição mais profunda na hierarquia (por exemplo, adaptativa.neu-ralnet ou adaptativa.genética) contêm classes relacionadas a um tipo específico de algoritmo adaptativo.
O ninho de pacotes é apenas uma ferramenta para organizar pacotes relacionados e não fornece direitos de acesso especial entre os pacotes.
O código de classe no pacote Adaptive.Genetic não pode acessar os membros no pacote adaptativo ou adaptativo.EuralNet que possuem direitos de acesso ao pacote, e o escopo do pacote é aplicável apenas a pacotes específicos. O ninho de pacotes pode agrupar pacotes relevantes e ajudar os programadores a encontrar a classe desejada no nível lógico de maneira mais conveniente, mas além disso, não traz outros benefícios.
Notas do pacote
O pacote também pode ter anotações. Mas o problema é que, como os pacotes são uma estrutura organizacional sem entidades de código -fonte e elas não têm definição real, elas não podem ser anotadas como classes ou métodos; portanto, a anotação do pacote só pode ser alcançada anotando a declaração de declaração do pacote no arquivo de origem. No entanto, pode haver apenas uma declaração de pacote em cada pacote que pode ter anotações que agem sobre ele.
Então, como você anota pacotes? De fato, o Java não força os programadores a usar uma maneira de lidar com a regra de "declaração de pacote anotada única". A maneira recomendada é criar um arquivo chamado Package-i Nfo.java no diretório de pacotes, no qual apenas as instruções do pacote e as anotações do pacote são armazenadas sem colocar mais nada. Por exemplo, o arquivo do pacote info.java para o pacote ATTL se parece com o seguinte:
@Packagespec (nome dois "att Project", versão = "1.0" @Developmentmentsite ("Atttr.Project.org") @DevelopmentModel ("Open-Source") pacote de pacote;PackagesPec, Developmentsite e Desenvolvimento OpmentModel são usados para modificar os tipos de anotação. Obviamente, eles têm estratégias de economia de tempo de execução. O arquivo package-info.java deve ser compilado com outros arquivos de origem no pacote.
Recomendamos colocar todas as informações relacionadas ao pacote no arquivo package-info.java. Se você fizer isso, poderá colocar os comentários do documento no início do arquivo, para que esses documentos sejam anotados como documentos do pacote.
Acesso ao pacote
Ao declarar a acessibilidade de classes de nível superior e interfaces de nível superior em pacotes, existem duas opções: acesso ao pacote (pacote) e acesso público (público). Aulas ou interfaces modificadas com o público podem ser acessadas por código fora da embalagem, enquanto os tipos não decorados com o público têm escopo de embalagem: eles podem ser acessados por outros códigos no mesmo pacote; Mas eles estão ocultos para códigos de pacote, mesmo em códigos de subpackagem. Ao declarar tipos, devemos declarar apenas esses tipos que outros programadores precisam usar como público e ocultar os tipos que pertencem aos detalhes da implementação do pacote. Essa tecnologia nos fornece grande flexibilidade e, como os programadores não confiam nesses tipos de detalhes de implementação que eles não podem acessar, podemos alterá -los livremente quando queremos alterar os detalhes da implementação.
Os membros da classe que não são declarados como públicos, protegidos ou privados podem ser acessados diretamente por qualquer código dentro do pacote, mas estão ocultos de fora do pacote. Em outras palavras, o modificador de acesso padrão é o "pacote", com exceção dos membros da interface, e seu modificador de acesso padrão é "público".
Campos ou métodos que não são declarados privados dentro de um pacote podem ser acessados por todos os outros códigos nesse pacote; portanto, as classes no mesmo pacote são consideradas "amigáveis" ou "confiáveis". Isso nos permite definir uma estrutura de aplicativo que combina código predefinido e código de espaço reservado, onde o código do espaço reservado é substituído por uma subclasse da classe Framework. Os códigos predefinidos podem usar modificadores de acesso ao pacote para que outros códigos colaborativos no pacote possam acessá-los diretamente, mas para usuários fora da embalagem, esses códigos são inacessíveis. No entanto, as subpackagens dos pacotes onde esses códigos estão localizados não são confiáveis e vice -versa. Por exemplo, o código modificado com o modificador de acesso ao pacote no pacote DIT não pode ser acessado pelo código em seu pacote filho Dit.dat e vice -versa.
Portanto, cada tipo define três contratos diferentes:
.publi. Contrato: define a principal função do tipo.
. Contrato protegido: define as funções disponíveis para subclasses para fins de especialização.
.package Contrato: define as funções que podem ser obtidas por outro código no pacote para obter a colaboração entre os tipos no pacote. Todos esses contratos exigem consideração e design cuidadosos.
Acessibilidade e método de cobertura
Somente métodos acessíveis em superclasses podem ser substituídos em subclasses. Se um método na superclasse não puder ser acessado, o método não poderá ser substituído na subclasse, mesmo que o método na subclasse tenha o mesmo nome que o método. Quando um método é chamado em tempo de execução, o sistema considera sua acessibilidade e, portanto, determina qual implementação está em execução.
O seguinte exemplo especialmente construído é explicado com mais clareza. Suponha que declaremos uma classe de base abstrata no pacote P1:
Pacote P1; {AB AB ABAB Public Resumo Classe AbstractBase Private void Pri () {print ("stractbase.pri ()"):} void Pac () {print ("stractbase.pac ()"); } Protected void pro () {print ("stractbase.pro ()"); } public void pub () {print ("stractbase.pub ()");} public final void show () PRI (); Pac (); pró(); pub(); }}Nesta classe, definimos 4 métodos, cada um com um modificador de acesso diferente, e o corpo do método apenas se identifica. O método mostra que chama esses 4 métodos no objeto atual, por sua vez. Ao aplicar esse método a diferentes objetos de subclasse, ele pode explicar qual implementação desses métodos é chamada.
Agora, definimos o concreto de classe, que estende a classe AbstractBase, mas está localizado no pacote P2:
Pacote P2; Importar P1.ABStractBase Public Class Concretel estende abstratoBase {public void Pri () {print ("concretel.pri ()");} public void Pac () {print ("concretel.pac ()");} public void proid () {Print ("concretel.pro ()");}; }Os 4 métodos na superclasse são redeclarados nesta classe e suas implementações são alteradas, que estão relatando que pertencem à classe Con-Cretel. Ao mesmo tempo, seus direitos de acesso foram alterados para o público para outro código para acessar. Executar o seguinte código
novo concreto (). Show ():
A seguinte saída será gerada:
AbstractBase.pri () abstractBase.pac () concretel.pro () concretel.pub ()
Como o método privado PRI não pode ser acessado por subclasses (ou outras classes), o método Show sempre chama a implementação do método PRI na classe AbstractBase. O método PAC com permissões de acesso ao pacote na classe AbstractBase não pode ser acessado pelo Concretel; portanto, a implementação do método PAC na classe concretel não pode substituir a definição na classe AbstractBase, portanto, o método de show chama o método abstractBase.pac. O método Pro e o método do pub são acessíveis na classe de concretel e também podem ser substituídos; portanto, o método do show chama a implementação desses dois métodos na classe de concretel.
Siga nosso pé, que significa classe concreto2 para estender o concreto de classe e, em seguida, colocamos -o no mesmo pacote P1 que a classe abstrataBase ':
Pacote P1; Importar p2.Concretel public class concrete2 estende concretel {public void Pri () {print ("concreto2.Pri ()");} public void Pac () {print ("concreto2.pac ()");} public void proid () {print ("concreto2.pro ()");} n);Como os métodos no concreto têm direitos de acesso público, eles podem ser acessados no concreto2 e cada método no concreto2 cobre seus métodos correspondentes separadamente. Além disso, como o concreto2 e o abstratoBase estão no mesmo pacote, o método abstratebase.pac também pode ser acessado no concreto2 e o método concreto2.pac pode ser substituído. Ligue para o método Show no objeto Concrete2, e o resultado da impressão é o seguinte:
AbstractBase.pri () concreto2.pac () concreto2.pro () concreto2.pub ()
Finalmente, definimos o concreto de classe 3 para estender o concreto da classe e colocá -lo no pacote P3:
pacote p3 importar p1.Concrete2; public class concrete3 estende concreto2 {public void Pri () {print ("concreto3.Pri ()");} public void Pac q {print ("concreto3.pac ()");} public void proid () {print ("concreto3.Pro ()");} public void pub () {("Chame o método Show no objeto Concrete3, e o resultado da impressão é o seguinte:
AbstractBase.pri () concreto3.pac () concreto3.pro () concreto3.pub ()
Aqui, o método concreto3.PAC parece substituir o método inacessível abstractBase.pac, mas, de fato, o método concreto3.pac substitui o método concreto2.pac e o método concreto2.pac substituem o método abstrateBase.pac, portanto, o método concreto3.pac substitui indiretamente o método abstractas.pac. Ao redigir o método PAC na classe concreto2 como tendo permissões de acesso público, ele pode ser acessado e substituído por qualquer subclasse.
Objetos e especificações do pacote
Os pacotes geralmente implementam algumas especificações e geralmente são de uma organização. Os objetos do pacote são diferentes de outros tipos de reflexão e não podem ser usados para criar ou operar pacotes, mas só podem servir como base de conhecimento para fornecer informações, que fornecem informações sobre as especificações implementadas pelo pacote (o título, o fornecedor e o número da versão) e as informações sobre a implementação do próprio pacote (o título, o fornecedor e a versão do pacote). Embora os pacotes geralmente venham de organizações individuais, as especificações que ele implementa (como bibliotecas de análise estatística) podem ser definidas por outras organizações. Os programas que usam pacotes podem precisar conhecer a versão da especificação implementada pelo pacote, para que as funções definidas apenas em uma determinada versão possam ser usadas. Da mesma forma, esses programas também podem precisar saber qual versão de implementação é fornecida, principalmente para lidar com possíveis falhas em diferentes versões. Alguns dos principais métodos da classe do pacote permitem o acesso a essas informações:
・ Strip public stri ng getName (): retorna o nome do pacote.
.public string getSpecificationTitle p: Retorna o título da especificação implementada pelo pacote. Se o título for desconhecido, retorne nulo,
.public string getSpecificationVersion (): retorna uma string que descreve as informações da versão da especificação implementada pelo pacote. Se as informações da versão forem desconhecidas, retorne nulo,
.public string getSpecificationVendor Q: Retorna o nome do fornecedor, que possui e mantém as especificações implementadas pelo pacote. Se o fornecedor for desconhecido, retorne nulo,
.public string getImpleRentationTitle (): Retorna o título da implementação fornecida pelo pacote. Se o título for desconhecido, ele retornará nulo, ・ public string getImplementationversion (): retorna uma string que descreve as informações da versão da implementação fornecida pelo pacote. Se as informações da versão forem desconhecidas, ele retornará nulo,
・ Public String getImplementationVendor (): Retorna o nome da organização (fornecedor) que fornece a implementação. Se a organização é desconhecida, retorne nulo,
Por exemplo, se extraímos essas informações do pacote java.lang em nosso sistema, obteremos os seguintes resultados:
Título da Especificação: Java Plataforma API Especificação Especificação Versão: 1.4 Specification Fornecedor: Sun Microsystems, Inc. Título da implementação: Java Runtime Environment Implementation Versão: 1.5.0_02 Fornecedor de implementação: Sun Microsystems, Inc.
O número da versão canônica consiste em números não negativos separados por delimitadores de período, como '' 2.0 '' ou '11 .0.12 '. Esse padrão nos permite chamar o método ISCompatiblewith para comparar o número da versão que segue esse padrão com o número da versão do pacote. Se o número da versão do pacote for maior ou igual ao número da versão do sucessor, o método retornará true. Essa comparação compara apenas um número separado pelo período por vez. Se algum desses números for menor que a posição correspondente no número da versão passada, as duas versões serão incompatíveis. Se um dos números da versão for mais longo que o outro, a parte que falta nos números da versão curta será considerada zero. Por exemplo, se o número da versão canônica do pacote for "1.4" e nós o comparamos com "1.2", "1.3.1 '. Ou" .1.81., Então true será retornado; mas se comparado com "1.4.2 '. ou" .5 ", false será retornado. Essa conclusão é tirada porque esse mecanismo de comparação assume que a versão de especificação é compatível com versões anteriores.
Não existe um formato especificado para o número da versão de implementação, porque diferentes organizações que fornecem a implementação definirão a versão de implementação de maneira diferente. A única comparação que pode ser feita entre as versões de implementação é testar se a versão é a mesma, onde não há suposição de compatibilidade com versões anteriores.
O pacote pode ser selado, o que significa que as classes não podem mais ser adicionadas ao pacote. Pacotes não selados podem conter classes de vários locais diferentes no caminho de pesquisa de classe, enquanto o conteúdo do pacote selado deve vir do mesmo local - um arquivo específico ou um local especificado por um URL. Existem duas maneiras de determinar se um pacote está selado:
.public boolean emitido P: Retorne Trueo se o pacote for selado
.Public boolean emitido (URL URL): retorne true se o pacote for selado para o URL fornecido, ou seja, as classes do pacote podem ser carregadas a partir deste URL fornecido. Se a classe no pacote não puder ser carregada de um determinado URL, ou o pacote não for selado, o FALSE será retornado e as informações de especificação e implementação do pacote geralmente são fornecidas como parte do arquivo de manifesto armazenado com o pacote - por exemplo, como parte do arquivo manifesto em um arquivo Java (JAR), como descrito na seção 25.9.2, “Arquivo Arquivo Quando uma aula em um pacote é carregada, essas informações são lidas pela pessoa. Um carregador de classe pode definir dinamicamente um objeto de pacote para a classe que deseja carregar:
.Potected Package Denepackage (nome da string, String Spectitle, String Specversion, String Specvendor, String ImplTitle, String Implversion, String Implvendor, URL Sealbase): Este método retornará um objeto de pacote com o nome do pacote e especificação e o valor da implementação definido. Se a fase de vedação do parâmetro for nula, o pacote não será selado; caso contrário, o pacote será selado para este URL: o objeto de pacote da classe deve ser definido antes que a classe seja definida e o nome do pacote deverá ser exclusivo no carregador de classe. Se o nome do pacote for repetido com o nome existente, o trabalho 11EGA1ArgumentException será lançado.
Podemos chamar o método getPackage do objeto de classe da classe fornecida para obter o objeto de pacote desta classe. Também podemos ligar para o pacote estático. Ambos os métodos estão relacionados ao carregador de classe que chama seu código, porque esses códigos chamarão os métodos Get-Package ou GetPackages do carregador de classe. Os métodos de carregadores de classe procurarão um carregador de classe específico e todos os seus carregadores de classe pai e, se nenhuma configuração for feita para o carregador de classe atual, o carregador de classe do sistema será usado no momento. Observe que, se o pacote for desconhecido, o método do carregador de classe retornará nulo porque nenhum tipo no pacote foi carregado no momento.