Prefácio
Em Java, um objeto deve ser inicializado corretamente antes de poder ser usado, que é estipulado pela especificação Java. Recentemente, descobri uma pergunta interessante, e a resposta para essa pergunta enganou meus olhos à primeira vista. Dê uma olhada nessas três categorias:
pacote com.ds.test; classe pública Upper {string upperstring; public Upper () {Initializer.initialize (this); }} pacote com.ds.test; classe pública mais baixa estende a parte superior {string abaixa = null; public inferior () {super (); System.out.println ("Upper:" + Upperstring); System.out.println ("Lower:" + abaixa); } public static void main (string final [] args) {new inferior (); }} pacote com.ds.test; public class Initializer {estático void Initialize (anupper superior final) {if (instância anupper de inferior) {inferior inferior = (inferior) anupper; inferior.lowerstring = "Lowerinited"; } anupper.upperstring = "Upperinited"; }} Que saída pode ser obtida executando a classe Lower ? Neste exemplo mínimo, toda a situação pode ser vista com mais facilidade, mas essa situação acontece na realidade e haverá muito código que distraia uma pessoa.
Enfim, a saída é assim:
Superior: UpperinitedLower: nulo;
Embora o tipo String seja usado no pequeno exemplo, o código real da classe Initializer possui um objeto delegado para registro, o mesmo que Lower - pelo menos Lower é a intenção. Mas, por algum motivo, não funciona ao executar o aplicativo. Em vez disso, o caminho padrão é usado e o objeto delegado não está definido (nulo).
Agora altere um pouco o código da Lower :
pacote com.ds.test; classe pública mais baixa estende superior {string abaixa; public inferior () {super (); System.out.println ("Upper:" + Upperstring); System.out.println ("Lower:" + abaixa); } public static void main (string final [] args) {new inferior (); }}A saída agora se parece com o seguinte:
Superior: UpperinitedLower: Lowerinited
Você encontrou a diferença no código?
Sim, este campo lowerString não está mais explicitamente definido para esvaziar. Por que isso torna isso diferente? De qualquer forma, o valor padrão do campo do tipo de referência (como String aqui) não é vazio? Claro que está vazio. Acontece que, embora essa ligeira mudança obviamente não altere o comportamento do código de forma alguma, isso torna o resultado diferente.
Então, o que exatamente aconteceu? Tudo fica claro ao verificar a ordem de inicialização:
1. main() chama o construtor Lower .
2. Uma instância de Lower está pronta. Significando que todos os campos são criados e preenchidos com valores padrão, por exemplo, o valor padrão do tipo de referência está vazio e o valor padrão do tipo booleano é false . No momento, não ocorre uma atribuição embutida ao campo.
3. O construtor da classe pai é chamado. Isso é imposto pelas características do idioma. Portanto, antes que qualquer outra coisa aconteça, o construtor do Upper é chamado.
4.Pupse este construtor executa e especifica uma referência à instância recém -criada do método Initializer.initialize() .
5. Initializer anexa uma nova string a dois campos ( upperString e lowerString ). Atribuir valores a esses dois campos usando uma instanceof suja de verificação de instância não é um padrão de design particularmente bom, mas também funciona, não se preocupe tanto. Quando isso acontece, as referências à upperString e lowerString não estão mais vazias.
6. A chamada para Initializer.initialize() é concluída e Upper também é concluído.
7. Agora está ficando interessante: a construção da instância Lower continua. Supondo que a atribuição =null não seja especificada explicitamente na declaração do campo lowerString , o construtor Lower retoma a execução e imprime duas seqüências conectadas ao campo.
No entanto, se houver uma operação que atribua explicitamente nulo, o processo de execução será ligeiramente diferente: quando o construtor da classe pai for concluído, qualquer inicialização da variável será realizada antes do restante dos construtores (consulte a seção 12.5 da especificação da linguagem Java). Nesse caso, a referência de string atribuída a lowerString anteriormente não recebe nulo novamente. Em seguida, continue executando a construção de funções restantes e agora imprima o valor da lowerString como: NULL.
Este é um ótimo exemplo, não apenas para facilitar nossa atenção a alguns detalhes sobre a criação de objetos (ou para saber onde verificar as especificações de codificação Java, impressas ou online), mas também para mostrar por que escrever as inicializações como essa é ruim. Não devemos nos preocupar com a subclasse do Upper. Por outro lado, se, por algum motivo, a inicialização de certos campos não puder ser feita na própria subclasse, isso exigirá apenas alguma variante de sua própria classe auxiliar de inicialização. Nesse caso, se você usar String lowString ou String lowerString = null realmente não há diferença, o que deveria ser será.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo seja de ajuda para estudar ou trabalhar de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar.