Já utilizamos o conceito de “objeto” antes, mas não discutimos a maneira específica como os objetos são armazenados na memória. Esta discussão levará ao importante conceito de “referência de objeto”.
referência de objeto
Continuamos usando a classe Human definida anteriormente e temos uma classe Test:
Copie o código do código da seguinte forma:
Teste de classe pública
{
público estático void principal(String[] args)
{
Humano aPerson = novo Humano(160);
}
}
classeHumano
{
/**
* construtor
*/
humano público (int h)
{
esta.altura = h;
}
/**
*acessador
*/
público int getHeight()
{
retorne esta altura;
}
/**
* mutador
*/
public void growHeight(int h)
{
esta.altura = esta.altura + h;
}
altura interna privada;
}
As classes podem ser chamadas externamente para criar objetos, como o acima na classe Test:
Copie o código do código da seguinte forma:
Humano aPerson = novo Humano(160);
Um objeto aPerson da classe Human é criado.
A afirmação acima é uma afirmação muito simples, mas temos muitos detalhes para entrar:
1. Primeiro observe o lado direito do sinal de igual. new abre espaço para objetos na memória. Especificamente, new abre espaço para objetos na pilha de memória. Neste espaço são armazenados os dados e métodos do objeto.
2. Observe o lado esquerdo do sinal de igual. aPerson refere-se a um objeto Humano, que é chamado de referência de objeto. Na verdade, aPerson não é o objeto em si, mas é semelhante a um ponteiro para o objeto. aPerson existe na pilha da memória.
3. Quando usamos o sinal de igual para atribuir um valor, o endereço do objeto criado no heap por new à direita é atribuído à referência do objeto.
A memória aqui se refere ao espaço de memória do processo Java virtualizado pela JVM (Java Virtual Machine). Para obter os conceitos de heap e pilha na memória, consulte Linux do programa ao processo.
A pilha pode ser lida mais rapidamente que o heap, mas os dados armazenados na pilha são limitados pelo intervalo válido. Na linguagem C, quando uma chamada de função termina, o quadro de pilha correspondente é excluído e os parâmetros e variáveis automáticas armazenados no quadro de pilha desaparecem. A pilha do Java também está sujeita à mesma restrição. Quando uma chamada de método termina, os dados armazenados na pilha pelo método serão apagados. Em Java, todos os objetos (comuns) são armazenados no heap. Portanto, o significado completo da palavra-chave new é criar um objeto no heap.
Objetos de tipos primitivos, como int e double, são armazenados na pilha. Quando declaramos um tipo básico, não há necessidade de novo. Uma vez declarado, Java armazena tipos primitivos de dados diretamente na pilha. Portanto, o nome da variável de um tipo básico representa os dados em si, não uma referência.
A relação entre referências e objetos é como uma pipa e uma pessoa. Quando olhamos para o céu (escrito no programa), o que vemos é uma pipa (referência), mas o que corresponde à pipa é uma pessoa (objeto):
Separação de referências e objetos referências apontam para objetos;
Embora referências e objetos sejam separados, todo nosso acesso aos objetos deve passar pela “porta” das referências, como acessar métodos de objetos através de reference.method(). Em Java, não podemos pular referências e tocar objetos diretamente. Por outro exemplo, se o membro de dados do objeto a for um objeto comum b, o membro de dados de a salva uma referência ao objeto b (se for uma variável de tipo básico, então o membro de dados de a salva a própria variável de tipo básico) .
Em Java, as referências desempenham o papel de ponteiros, mas não podemos modificar diretamente o valor do ponteiro, como adicionar 1 ao valor do ponteiro, como na linguagem C. Só podemos realizar operações em objetos através de referências. Esse design evita muitos erros que os ponteiros podem causar.
atribuição de referência
Quando atribuímos uma referência a outra referência, estamos na verdade copiando o endereço do objeto. Ambas as referências apontarão para o mesmo objeto. Por exemplo, dummyPerson=aPerson resultará em:
Um objeto pode ter múltiplas referências (uma pessoa pode empinar várias pipas). Quando um programa modifica um objeto através de uma referência, a modificação é visível através de outras referências. Podemos usar a seguinte classe Test para testar o efeito real:
Copie o código do código da seguinte forma:
Teste de classe pública
{
público estático void principal(String[] args)
{
Humano aPerson = novo Humano(160);
DummyPerson humano = aPerson;
System.out.println(dummyPerson.getHeight());
aPerson.growHeight(20);
System.out.println(dummyPerson.getHeight());
}
}
Nossas modificações em aPerson afetarão dummyPerson. Na verdade, essas duas referências apontam para o mesmo objeto.
Portanto, atribuir uma referência a outra referência não copia o próprio objeto. Devemos encontrar outros mecanismos para copiar objetos.
Coleta de lixo
À medida que a chamada do método termina, as variáveis de referência e de tipo primitivo são limpas. Como o objeto reside no heap, a memória ocupada pelo objeto não será limpa quando a chamada do método terminar. O espaço do processo pode rapidamente ficar preenchido com objetos sendo criados. Java possui um mecanismo integrado de coleta de lixo para limpar objetos que não são mais usados para recuperar espaço de memória.
O princípio básico da coleta de lixo é que quando há uma referência apontando para um objeto, o objeto não será reciclado; quando não há referência apontando para um objeto, o objeto é limpo; O espaço que ocupa é recuperado.
A figura acima assume o status da memória na JVM em um determinado momento. O Objeto Humano possui três referências: aPerson e dummyPerson da pilha, e o presidente, um membro de dados de outro objeto. O Club Object não tem referência. Se a coleta de lixo for iniciada neste momento, o Club Object será esvaziado e a referência do Objeto Humano (presidente) do Club Object também será excluída.
A coleta de lixo é um mecanismo importante em Java, que afeta diretamente a eficiência operacional do Java. Entrarei em detalhes sobre isso mais tarde.
Passagem de parâmetros
Quando separamos os conceitos de referências e objetos, o mecanismo de passagem de parâmetros dos métodos Java é na verdade muito claro: a passagem de parâmetros Java é por valor. Ou seja, quando passamos um parâmetro, o método irá obter uma cópia do parâmetro.
Na verdade, um dos parâmetros que passamos é uma variável do tipo básico e o outro é uma referência ao objeto.
A passagem por valor para variáveis de tipo primitivo significa que a própria variável é copiada e passada para o método Java. Modificações de variáveis por métodos Java não afetarão as variáveis originais.
Passar por valor significa que o endereço do objeto é copiado e passado para o método Java. O acesso ao método Java baseado nesta referência afetará o objeto.
Há outra situação que vale a pena mencionar aqui: usamos new dentro do método para criar um objeto e retornar uma referência ao objeto. Se o retorno for recebido por uma referência, como a referência do objeto não é 0, o objeto ainda existe e não será coletado como lixo.
Resumir
novo
referência, objeto
Condições para coleta de lixo
Parâmetros: passados por valor