1. Variáveis ​​de referência

Na linguagem Java, existem dois tipos de variáveis: variáveis ​​primitivas e tudo mais. Por acaso, vamos falar sobre "todo o resto" agora.

Na verdade, seria mais correto dizer que existem variáveis ​​primitivas e variáveis ​​de referência . Então, quais são essas variáveis ​​de referência?

Ao contrário dos tipos primitivos, cujas variáveis ​​armazenam valores diretamente, as variáveis ​​de referência armazenam referências a objetos. Ou seja, existe um objeto em algum lugar da memória e a variável de referência simplesmente armazena o endereço desse objeto na memória (uma referência ao objeto).

Somente tipos primitivos armazenam valores diretamente dentro de variáveis. Todos os outros tipos armazenam apenas uma referência de objeto . A propósito, você já encontrou dois desses tipos de variáveis ​​— Stringvariáveis ​​e variáveis ​​de matriz .

Tanto um array quanto uma string são objetos armazenados em algum lugar da memória. Stringvariáveis ​​e variáveis ​​de matriz armazenam apenas referências a objetos.

Variáveis ​​de referência em Java

int a, int b and double dsão variáveis ​​primitivas que armazenam seus valores dentro de si.

Uma String strvariável é uma referência e armazena o endereço (referência) para um Stringobjeto na memória.

Ao atribuir um valor primitivo a uma variável de tipo primitivo, seu valor é copiado (duplicado). Ao atribuir uma variável de referência, apenas o endereço do objeto é copiadoo próprio objeto não é copiado .


2. Do que se tratam as referências?

Qual é a diferença fundamental entre variáveis ​​de referência e variáveis ​​primitivas?

Uma variável primitiva é como uma caixa: você pode armazenar algum valor nela. Uma variável de referência é mais como um pedaço de papel com um número de telefone.

Um carro vs chaves do carro

Imagine que você decide dar um carro para seu amigo no aniversário dele. Você não vai embrulhá-lo em uma caixa e carregá-lo com você: o carro é grande demais para isso.

É muito mais conveniente apresentar apenas as chaves do carro em uma caixa grande o suficiente para contê-las. Seu amigo vai entender tudo quando tirar as chaves da caixa. Não há necessidade de carregar o carro inteiro com você quando você pode simplesmente entregar as chaves.

Uma pessoa versus seu número de telefone

Ou aqui está outra comparação: uma pessoa e seu número de telefone. Um número de telefone não é a pessoa, mas um número de telefone pode ser usado para ligar para ela, pedir algumas informações ou fornecer instruções.

Da mesma forma, uma referência é usada para interagir com um objeto. Todos os objetos interagem uns com os outros usando referências. Em vez de "trocar pessoas", simplesmente trocamos números de telefone.

Ao atribuir um valor a uma variável primitiva, seu valor é copiado (duplicado). Ao atribuir um valor a uma variável de referência, apenas o endereço (número de telefone) do objeto é copiado — o próprio objeto não é copiado.

Uma referência oferece mais uma vantagem: você pode passar uma referência de objeto para algum método, e o método poderá modificar (alterar) o objeto usando a referência a ele, chamando seus métodos e acessando dados dentro do objeto.


3. Atribuição de referências

Ao atribuir variáveis ​​de referência, apenas o endereço do objeto na memória é atribuído. Os próprios objetos não aparecem ou desaparecem.

Essa abordagem evita a cópia de grandes quantidades de memória. Se você precisa passar um objeto muito grande para um método, basta passarmos a referência do objeto e pronto. A referência ocupa muito menos espaço.

Atribuindo referências

O tamanho de todas as variáveis ​​de referência (independente de seu tipo) é o mesmo — 4 bytes (como um int). Mas! Se seu aplicativo estiver sendo executado em uma máquina Java de 64 bits, todas as referências terão 8 bytes (64 bits) de tamanho.

Além do mais, as referências só podem ser atribuídas umas às outras. Você não pode alterar referências ou atribuir valores arbitrários a variáveis ​​de referência:

Código Descrição
String hello = "Hello";
String s = hello;
isso é permitido
String hello = "Hello";
hello++;
Mas isso não é permitido
String hello = 0x1234;
E isso não é permitido

4. Uma nullreferência

E o que uma variável de referência armazena se nada foi atribuído a ela ainda?

Ele armazena uma referência nula . nullé uma palavra-chave Java especial que significa a ausência de uma referência (uma referência vazia). O nullvalor pode ser atribuído a qualquer variável de referência.

Todas as variáveis ​​de referência são, nulla menos que tenham algum tipo de referência atribuída a elas.

Exemplos:

Código Descrição
class Person
{
   public static String name;
   public static int age;
}


A String namevariável tem um valor padrão: null.
A int agevariável tem um valor padrão: 0.

Variáveis ​​locais que não receberam um valor são consideradas não inicializadas para tipos primitivos e de referência.

Se uma variável armazena uma referência a algum objeto e você deseja limpar o valor da variável, basta atribuir a ela uma referência nula.

Código Descrição
String s = null;
s = "Hello";
s = null;
slojas null.
sarmazena uma referência a um objeto de cadeia
sde caracteres null.

5. Passando referências a métodos

Se um método tiver parâmetros que são tipos de referência , os valores serão passados ​​para o método da mesma forma que ao trabalhar com variáveis ​​sem referência. O parâmetro é simplesmente atribuído ao valor da outra variável.

Exemplo:

Código Descrição
class Solution
{
   public static void fill(String[] array, String value)
   {
      for (int i = 0; i < array.length; i++)
        array[i] = value;
   }

   public static void main(String[] args)
   {
     String[] data = new String[10];
     fill(data, "Hello");
   }
}


O fillpreenche o array passado ( array) com o valor passado ( value).

Quando o fillmétodo é chamado, o arrayparâmetro recebe uma referência ao dataarray. A valuevariável recebe uma referência ao objeto string ("Hello").

É assim que a memória se parece antes de chamar o fill método:

Passando referências a métodos

É assim que a memória se parece quando o fill método está em execução :

Passando referências para métodos 2

As variáveis data​​e arrayreferem-se (armazenam referências) ao mesmo contêiner na memória.

A valuevariável armazena uma referência ao objeto string ( "Hello").

As células da matriz também armazenam apenas referências ao "Hello"objeto.

Na verdade, nenhum objeto é duplicado — apenas referências são copiadas.



6. Comparação com a linguagem C/C++

Em entrevistas, às vezes os programadores Java são questionados sobre como os dados são passados ​​para os métodos em Java. E às vezes a dúvida é se os dados são passados ​​por referência ou por valor?

Esta questão vem de C++, mas não é muito significativa em Java . Em Java, os parâmetros sempre recebem simplesmente os valores dos argumentos. Então a resposta correta seria " por valor ".

Mas esteja preparado para explicar sua posição , pois você pode ouvir imediatamente a resposta: "tipos primitivos são passados ​​por valor e tipos de referência são passados ​​por referência."

A origem desse problema decorre do fato de que muitos programadores Java eram programadores C++ no passado. Nessa linguagem de programação, a questão de como os parâmetros são passados ​​para os métodos era muito importante.

Em Java, tudo é inequívoco: tipos primitivos armazenam valores e tipos de referência também armazenam um valor — uma referência. É uma questão de saber se uma variável é considerada um valor .

Em C++, uma variável pode armazenar tanto uma referência a um objeto quanto o próprio objeto. O mesmo acontecia com os tipos primitivos: uma variável primitiva poderia armazenar um valor ou declarar a variável como uma referência a um arquivo int. Portanto, para evitar confusão, os programadores C++ sempre se referem ao objeto como uma referência como uma referência e o próprio objeto como um valor.

Em C++, você pode facilmente ter a situação em que uma variável contém um objeto, mas a outra contém uma referência a esse objeto. Assim, a questão do que uma variável armazena — o próprio objeto ou apenas uma referência a ele — era muito importante. Quando um objeto foi passado para um método, ele foi copiado (se passado por valor), e não copiado (se passado por referência).

Em Java essa dualidade não existe, então a resposta correta é: os argumentos são passados ​​para os métodos Java por valor . Só que quando estamos falando de variáveis ​​de referência, esse valor é uma referência.