O objetivo deste curso é ajudá -lo a usar o Java com mais eficiência. Existem alguns tópicos avançados discutidos, incluindo criação de objetos, simultaneidade, serialização, reflexão e outros recursos avançados. Este curso guiará sua jornada de proficiência em Java.
1. Introdução
No ranking da linguagem de programação TioBe, a linguagem Java desenvolvida pela Sun em 1995 é uma das linguagens de programação mais amplamente usadas no mundo. Como uma linguagem geral de programação, a linguagem Java é muito atraente para os engenheiros de desenvolvimento de software devido ao seu poderoso kit de ferramentas e ambiente de tempo de execução, sintaxe simples, suporte rico em plataforma (escrito de uma só vez, execute em todos os lugares) e suporte à comunidade extremamente ativa.
Nesta série de artigos, o conteúdo avançado relacionado ao Java é coberto, por isso supõe -se que o leitor já tenha conhecimento básico da linguagem. Este não é um manual de referência completo, mas um guia exaustivo para levar suas habilidades para o próximo nível.
Este curso contém um grande número de trechos de código. Para fazer comparações, algumas outras partes fornecerão exemplos de Java 7 e Java 8 ao mesmo tempo.
2. Exemplo de construção
Como uma linguagem orientada a objetos, a criação de objetos é talvez um dos conceitos mais importantes da língua Java. Um construtor desempenha um papel importante na inicialização das instâncias de objetos, e o Java fornece várias maneiras de definir construtores.
2.1 Método de construção implícito (gerado)
O Java permite que nenhum construtores seja declarado ao definir classes, e isso não significa que não haja construtor. Vejamos a definição da seguinte classe:
pacote com.javacodegeeks.advanced.construction; classe pública noconstructor {}Esta classe não define um construtor, mas o compilador Java gerará implicitamente um para ele, permitindo -nos usar a nova palavra -chave para criar novas instâncias de objetos.
NOCOSTRUTOR FINAL NOCOSTRUTORINSTANCE = new Noconstructor ();
2.2 Método de construção sem parâmetros
O construtor sem parâmetros é a maneira mais fácil de substituir a compilação Java e gerar construtores por declarações explícitas.
pacote com.javacodegeeks.advanced.construction; public class NoargConstructor {public noargconstructor () {// Body Body aqui}}Ao criar uma nova instância de objeto usando a nova palavra -chave, o construtor acima será chamado.
2.3 Método de construção do tipo parâmetro
O método de construção de parâmetros é o mais interessante e amplamente utilizado, e a criação de novas instâncias é personalizada especificando parâmetros. O exemplo a seguir define um construtor com dois parâmetros.
pacote com.javacodegeeks.advanced.construction; public class construtorwitherguments {public construtorwitharguments (string final arg1, string final arg2) {// corpo construtor aqui}}Nesse cenário, ao usar a nova palavra -chave para criar uma instância, dois parâmetros definidos no método de construção precisam ser fornecidos ao mesmo tempo.
Final ConstructorWitHarguments ConstructorWitherguments = new ConstructorWitherguments ("Arg1", "Arg2");Curiosamente, os construtores podem ser chamados um para o outro através dessa palavra -chave. Na prática, é recomendável encadear múltiplos construtores usando isso para reduzir a duplicação de código e ter uma única entrada de inicialização com base no objeto. Como exemplo, o código a seguir define um construtor com apenas um parâmetro.
public construtorwitharguments (string final arg1) {this (arg1, null);}2.4 Inicialize o bloco de código
Além de construir métodos, o Java também fornece a lógica a ser inicializada, inicializando os blocos de código. Embora esse uso seja raro, não é prejudicial saber mais sobre isso.
pacote com.javacodegeeks.advanced.construction; public class InitializationBlock {{// Código de inicialização aqui}}Por outro lado, a inicialização dos blocos de código também pode ser considerada métodos de construção implícitos sem parâmetros. Em uma classe específica, os blocos de código de inicialização múltiplos podem ser definidos e são chamados na ordem em que estão no código quando executados, conforme mostrado no código a seguir:
pacote com.javacodegeeks.advanced.construction; public class InitializationBlocks {{// Código de inicialização aqui} {// Código de inicialização aqui}}Realmente inicializando os blocos de código não deve substituir o construtor, mas eles podem aparecer simultaneamente. Mas lembre -se de que o código de inicialização será executado antes que a chamada do método do construtor seja em breve.
pacote com.javacodegeeks.advanced.construction; public class InitializationBlockandConstructor {{// Código de inicialização aqui} public InitializationBlockandConstructor () {}}2.5 Verifique se a construção de valores padrão
O Java fornece uma garantia de inicialização definitiva e os programadores podem usar o resultado da inicialização diretamente. Instâncias e variáveis de classe não inicializadas (estáticas) serão inicializadas automaticamente para os valores padrão correspondentes.
Digite o valor padrão
booleanfalse
byte0
Short0
int0
long0l
CHAR/U0000
float0.0f
Double0.0d
Referência de objeto NULL
Tabela 1
Usamos o exemplo a seguir para verificar os valores padrão na tabela acima:
pacote com.javacodegeeks.advanced.construction; public class Initialização comdefaults {private boolean booleanMember; Byte Privado Bytemember; Membro curto privado; private int intmember; Privado Longo Longo Longo; Charmember particular de char; Float FloatMember particular; Double Doublember privado; objeto privado referenceMember; public InitializationWithDefaults () {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 =" + caractere.codepointat (novo char [] {Charmember}, 0)); System.out.println ("floatmember =" + floatmember); System.out.println ("DoublemEmber =" + Doublember); System.out.println ("referenceMember =" + referenceMember); }}Depois de instantar o objeto usando a nova palavra -chave:
Inicialização final ATENSATIVA DE INICIALIZAÇÃO ACIMENTE
Você pode ver o resultado da saída do console da seguinte forma:
booleanMember = falseByTemember = 0ShortMember = 0IntMember = 0longMember = 0CharmEmber = 0FloatMember = 0.0DOUBMEMEMBER = 0.0ReferenceMember = NULL
2.6 Visibilidade
O construtor segue as regras de visibilidade de Java e pode determinar se o construtor pode ser chamado em outras classes por meio de modificadores de controle de acesso.
Visibilidade do pacote modificador Visibilidade da subclasse visibilidade pública
public visível visível visível visível visível visível
Visível visível protegido invisível invisível invisível
<Sem modificador> visível, não visível, não visível
Private Invisible Invisible Invisible Invisible Tabela 2
2.7 Reciclagem de lixo
O Java (JVM a ser preciso) possui um mecanismo automático de coleta de lixo. Simplificando, quando um novo objeto for criado, ele alocará automaticamente seus intrínsecos; Então, quando o objeto não for mais referenciado, eles serão destruídos automaticamente e a memória correspondente será reciclada.
A coleta de lixo Java adota um mecanismo de reciclagem geracional e baseia -se na suposição de que "a maioria dos objetos tem vida curta" (ou seja, eles não serão recitados logo após a criação do objeto, para que possam ser destruídos com segurança). A maioria dos programadores habitualmente acredita que a criação de objetos em Java é muito ineficiente; portanto, eles devem evitar a criação de novos objetos o máximo possível. De fato, esse entendimento está errado. A sobrecarga de criar objetos em Java é bastante baixa e rápida. A enorme sobrecarga da geração real é objetos desnecessários de sobrevivência a longo prazo, para que eles sejam migrados para a velhice e farão com que o stop-the World ocorra.
2.8 Finalizadores de objetos
Conversamos sobre os tópicos relacionados aos métodos de construção e inicialização de objetos, mas não mencionamos seu lado negativo: destruição de objetos. Principalmente porque o Java usa mecanismos de coleta de lixo para gerenciar o ciclo de vida dos objetos, destruindo objetos desnecessários e liberando a memória necessária se torna de responsabilidade da coleta de lixo.
No entanto, o Java ainda fornece outro recurso semelhante a um finalizador de destruidores, que assume a responsabilidade de limpar vários recursos. O Finalizador é geralmente visto como uma coisa perigosa (porque pode trazer uma variedade de efeitos colaterais e problemas de desempenho). Geralmente, o Finalizador não é necessário, portanto, tente evitá -lo (exceto em cenários raros que contêm um grande número de objetos nativos). A sintaxe Try-With-RESOURCES e a interface autoclosável introduzida no Java 7 pode ser usada como alternativas aos finalizadores, e o seguinte código conciso pode ser escrito:
Tente (Final InputStream em = files.NewInputStream (Path)) {// Código aqui}3. Inicialização estática
Acima, aprendemos sobre a construção e a inicialização das instâncias de classe. Além disso, o Java também suporta a construção de inicialização de nível de classe, chamada inicialização estática. A inicialização estática é semelhante ao bloco de código de inicialização descrito acima, exceto que existem modificações adicionais de palavras -chave estáticas. Deve -se notar que a inicialização estática será realizada apenas uma vez quando a classe for carregada. Exemplos são os seguintes:
Semelhante à inicialização dos blocos de código, vários blocos de inicialização estática podem ser definidos em uma classe e sua posição na classe determina a ordem em que são executados na inicialização. Exemplos são os seguintes;
pacote com.javacodegeeks.advanced.construction; public class StaticinitializationBlocks {static {// Código de inicialização estática aqui} estático {// Código de inicialização estática aqui}}}Como os blocos de inicialização estática podem ser acionados por vários threads executando em paralelo (quando a classe é carregada inicialmente), o tempo de execução da JVM garante que o código inicializado seja executado apenas uma vez de maneira segura.
4. Modo construtor
Uma variedade de padrões fáceis de entender (criadores) foram introduzidos na comunidade Java ao longo dos anos. Abaixo, aprenderemos alguns dos mais populares: modo singleton, modo de classe auxiliar, modo de fábrica e injeção de dependência (também conhecida como inversão de controle).
4.1 Modo Singleton
Singleton é uma longa história, mas um modelo controverso na comunidade de desenvolvimento de software. O conceito central do padrão de singleton é garantir que a qualquer momento uma determinada classe seja criada apenas um objeto. Embora pareça simples, há muita discussão sobre como criar objetos de uma maneira correta e segura por threads. O código a seguir mostra uma versão simples da implementação do padrão Singleton:
pacote com.javacodegeeks.advanced.construction.patterns; public class Nivesingleton {private static nivesingleton instância; private Nivesingleton () {} public static Nivesingleton getInstance () {if (instance == null) {instance = new Nivesingleton (); } Instância de retorno; }}Há pelo menos um problema com o código acima: vários objetos podem ser criados em um cenário de simultaneidade com vários threads. Uma maneira razoável de implementar (mas não o carregamento atrasado) é usar a propriedade estática da classe. do seguinte modo:
Propriedade final da classe.package com.javacodegeeks.advanced.construction.patterns; classe pública Eagersingleton {private estático final Eagersingleton Instância = new Eagersingleton (); private EagersingLeton () {} public static Eagersingleton getInstance () {retorna instância; }}Se você não deseja desperdiçar recursos valiosos e deseja que os objetos de singleton sejam criados apenas quando são realmente necessários, precisará usar um método de sincronização explícito. Esse método pode reduzir a simultaneidade em ambientes multithread (mais detalhes sobre a simultaneidade de Java serão descritos nas melhores práticas avançadas de 9 concursos avançadas).
pacote com.javacodegeeks.advanced.construction.patterns; classe pública Lazysingleton {private Static Lazysingleton Instância; private lazysingleton () {} public static sincronizado lazysingleton getInstance () {if (instance == null) {instance = new lazysingleton (); } Instância de retorno; }}Atualmente, os padrões de singleton não são mais considerados uma boa escolha em muitos cenários, porque facilitam o teste do código. Além disso, a geração de modo de injeção de dependência também torna o modo singleton desnecessário.
4.2 Ferramentas/classes auxiliares
A classe de ferramentas/padrão de classe de ajuda é bastante popular entre os desenvolvedores de Java. Seu conceito central é usar classes não institalizadas (declarando construtores privados), final opcional (mais detalhes sobre a declaração de classes finais serão introduzidos nos métodos-chave Java Advanced 3 Class and Interface) e métodos estáticos. Exemplos são os seguintes:
pacote com.javacodegeeks.advanced.construction.patterns; helperclass de classe final pública {private helperclass () {} public static void helperMethod1 () {// Método Body aqui} helpermethod de vazio estático public estático () {// Método aqui}}Muitos desenvolvedores experientes acreditam que esse padrão tornará as classes de ferramentas um contêiner para vários métodos irrelevantes. Como alguns métodos não têm um posicionamento adequado, mas precisam ser usados por outras classes, eles serão colocados erroneamente na classe de ferramentas. Esse design também deve ser evitado na maioria dos cenários: sempre haverá maneiras melhores de reutilizar o código, mantendo o código claro e conciso.
4.3 Modelo de fábrica
O modelo de fábrica provou ser uma ferramenta extremamente poderosa para os desenvolvedores, e há muitas maneiras de implementá -lo em Java: métodos de fábrica e fábricas abstratas. O exemplo mais fácil é usar o método estático para retornar uma instância de uma classe específica (método de fábrica), como segue:
pacote com.javacodegeeks.advanced.construction.patterns; public class Book {private Book (título final da string) {} public static Book NewBook (título final da string) {return New Book (título); }}Embora o uso desse método possa melhorar a legibilidade do código, geralmente é controverso que seja difícil fornecer ao método de fábrica do Newbook cenários mais ricos. Outra maneira de implementar o padrão de fábrica é usar interfaces ou classes abstratas (fábricas abstratas). Como segue, definimos uma interface de fábrica:
Public Interface BookFactory {Book NewBook ();}Dependendo da galeria de fotos, podemos ter muitas implementações diferentes de Newbook:
public class Library implementa BookFactory {@Override public Book NewBook () {return New Paperbook (); }} classe pública KindleLibrary implementa BookFactory {@Override public Book NewBook () {return New Kindlebook (); }}Agora, diferentes implementações do BookFactory bloqueiam as diferenças em livros específicos, mas fornecem um método geral do NewBook.
4.4 Injeção de dependência
A injeção de dependência (também conhecida como inversão de controle) é considerada pelos designers de classe como uma boa prática de design: se algumas instâncias de classe dependem de instâncias de outras classes, as instâncias dependentes devem ser fornecidas (injetadas) através de métodos construtores (ou métodos, políticas, etc.), e não pela própria instância. Vamos dar uma olhada no seguinte código:
pacote com.javacodegeeks.advanced.construction.patterns; importar java.text.dateFormat; importar java.util.date; public classe dependente {private dateFormat format = dateFormat.getDateInstance (); public string format (data final) {retorna format.format (data); }}A classe dependente requer uma instância da classe DateFormat e é obtida pelo DateFormat.getDateInstance () ao instantar o objeto. Uma maneira melhor deve fazer a mesma coisa construindo os parâmetros do método:
pacote com.javacodegeeks.advanced.construction.patterns; importar java.text.dateFormat; importar java.util.date; public classe dependente {private dateFormat Format; public dependente (formato final de data de data) {this.format = formato; } public string format (data final) {return format.format (data); }}No exemplo acima, todas as dependências da instância da classe são fornecidas externamente, facilitando o ajuste de data de data e fácil de gravar o código de teste.