Como você parece saber, a resposta acima também deixa claro que os objetos complementares são traduzidos para classes, e a classe que os declara mantém uma referência estática ao objeto da classe complementar, algo como a seguir:
public static final MyClass.Companion Companion = new MyClass.Companion(null);
Agora a pergunta
Os objetos complementares permanecem na memória durante o ciclo de vida do aplicativo
como a classe declarante possui uma static
referência à classe complementar, a pergunta se reduz ao tempo de vida dos static
campos na jvm class
e a resposta está na especificação da JVM , mas a especificação é um pouco seca na explicação, por isso estou adicionando alguns trechos do livro Inside a Java Virtual Machine .
Como no seu exemplo, digamos que temos um class
objeto complementar com nada além de um único.
A primeira pergunta é quando um objeto da classe complementar será criado? ou quando os static
campos são inicializados?
texto relevante do livro . (por contexto, o livro está falando sobre o procedimento de carregamento de classe)
Inicialização
A etapa final necessária para preparar uma classe ou interface para seu primeiro uso ativo é a inicialização, o processo de configuração de variáveis de classe com seus valores iniciais adequados. Como usado aqui, um valor inicial "adequado" é o valor inicial desejado pelo programador para uma variável de classe. Um valor inicial adequado contrasta com o valor inicial padrão dado às variáveis de classe durante a preparação. Como descrito acima, a máquina virtual atribui valores padrão com base apenas no tipo de cada variável. Os valores iniciais adequados, por outro lado, são baseados em algum plano mestre conhecido apenas pelo programador. No código Java, um valor inicial adequado é especificado por meio de um inicializador de variável de classe ou inicializador estático.
Portanto, sabemos que, uma vez MyClass
carregado e inicializado, o objeto da classe complementar será criado.
mas o que causaria o carregamento da JVM MyClass
?
A especificação Java Virtual Machine oferece às implementações flexibilidade no tempo de carregamento e vinculação de classe e interface, mas define estritamente o tempo de inicialização. Todas as implementações devem inicializar cada classe e interface em seu primeiro uso ativo. Um uso ativo de uma classe é:
A invocação de um construtor em uma nova instância da classe
A criação de uma matriz que tem a classe como um tipo de elemento
A invocação de um método declarado pela classe (não herdada de uma superclasse)
4 O uso ou atribuição de um campo declarado pela classe (não herdado de uma superclasse ou super interface), exceto para campos que são estáticos e finais, e são inicializados por uma expressão constante em tempo de compilação
Portanto, conforme o quarto ponto, quando você faz MyClass.foo()
do kotlin ou MyClass.Companion.foo()
, nesse momento, MyClass
ele estará carregado e pronto. (Provavelmente muito cedo)
Observe que, neste ponto, nenhum objeto MyClass
existe, ou seja, não usamos expressão MyClass()
.
Isso significa que os static
campos permanecerão na memória enquanto o aplicativo estiver em execução?
Eles podem ser coletados como lixo se o tipo de declaração for descarregado; no nosso caso, se a JVM ou ART (no android) descarregar MyClass
, existe a possibilidade de que o objeto complementar seja coletado como lixo.
A JVM Spec tem o seguinte a dizer sobre o descarregamento de classe
Uma implementação da linguagem de programação Java pode descarregar classes.
Uma classe ou interface pode ser descarregada se, e somente se, o seu carregador de classes definidor puder ser recuperado pelo coletor de lixo, conforme discutido em §12.6.
Classes e interfaces carregadas pelo carregador de inicialização não podem ser descarregadas.
Na aula de praticidade, o descarregamento quase (eu disse quase) nunca acontece; portanto , os objetos complementares permanecerão na memória durante o ciclo de vida do aplicativo .