1. Zmienne referencyjne

W języku Java zmienne mogą być dwojakiego rodzaju: zmienne typu pierwotnego i wszystkie inne. To dotyczy „wszystkich innych”, o których teraz porozmawiamy.

W rzeczywistości bardziej poprawne byłoby stwierdzenie, że istnieją zmienne typu pierwotnego i zmienne referencyjne . Czym więc są te zmienne referencyjne?

W przeciwieństwie do typów pierwotnych, które umożliwiają przechowywanie wartości bezpośrednio w zmiennych, zmienne typu referencyjnego przechowują odniesienia do obiektów. Te. gdzieś w pamięci znajduje się obiekt, a zmienna referencyjna po prostu przechowuje adres tego obiektu w pamięci (odniesienie).

Wartości bezpośrednio wewnątrz zmiennych przechowują tylko typy pierwotne , wszystkie inne typy przechowują tylko odniesienie do obiektu . Wcześniej nawiasem mówiąc, spotkałeś się już z dwoma takimi typami zmiennych – są to zmienne typu Stringi zmienne typu tablicowego .

Zarówno tablica, jak i ciąg znaków są obiektami przechowywanymi gdzieś w pamięci. Zmienne typu Stringi zmienne tablicowe przechowują tylko odwołania do obiektów.

Zmienne int a, int b и double dsą prymitywne i przechowują wartość w sobie.

Zmienna String strjest zmienną referencyjną i przechowuje adres (referencję) obiektu typu Stringw pamięci.

Podczas przypisywania wartości pierwotnej do zmiennej typu pierwotnego jej wartość jest kopiowana (duplikowana). Przy przypisywaniu do zmiennej referencyjnej kopiowany jest tylko adres obiektu , podczas gdy sam obiekt nie jest kopiowany .


2. Istota linków

Jaka jest podstawowa różnica między zmiennymi referencyjnymi a zmiennymi pierwotnymi?

Zmienna pierwotna jest jak pudełko: można w niej przechowywać pewną wartość. Zmienna referencyjna jest bardziej jak kartka papieru z numerem telefonu.

samochód kontra kluczyki do samochodu

Wyobraź sobie, że postanawiasz podarować znajomemu samochód na urodziny. Nie zapakujesz go w pudełko i nie będziesz woził ze sobą: samochód jest na to za duży.

O wiele wygodniej jest zabrać ze sobą tylko kluczyki do samochodu i wystarczająco pojemny dla nich box. A twój przyjaciel wszystko zrozumie, kiedy wyciągnie klucze z pudełka. Nie musisz nosić ze sobą całego samochodu, gdy możesz po prostu przekazać kluczyki.

Mężczyzna kontra jego numer telefonu

Lub inna opcja: osoba i jej numer telefonu. Numer telefonu nie jest samą osobą, ale numer telefonu może być używany do dzwonienia do niego, proszenia go o jakieś informacje, wydawania poleceń.

Łącze służy również do interakcji z obiektem. Wszystkie obiekty oddziałują na siebie za pomocą łączy. Zamiast „wymiany ludzi” wystarczy wymienić się numerami telefonów.

Podczas przypisywania wartości do zmiennej pierwotnej jej wartość jest kopiowana (duplikowana). Podczas przypisywania wartości do zmiennej referencyjnej kopiowany jest tylko adres obiektu („numer telefonu”), podczas gdy sam obiekt nie jest kopiowany.

Referencja ma jeszcze jedną zaletę: możemy przekazać referencję do obiektu jakiejś metodzie, a ta metoda będzie mogła modyfikować (zmieniać) nasz obiekt, korzystając z referencji do niego, wywołując jego metody i uzyskując dostęp do danych wewnątrz obiektu.


3. Przydział referencji

Przypisanie zmiennych referencyjnych po prostu przypisuje adres obiektu w pamięci. Same obiekty nie pojawiają się ani nie znikają.

Takie podejście pozwala uniknąć kopiowania dużych ilości pamięci. Jeśli trzeba gdzieś przekazać bardzo duży obiekt, po prostu przekazujemy do tej metody referencję do obiektu i to wszystko. Link zajmuje znacznie mniej miejsca.

Przypisanie łącza

Rozmiar wszystkich zmiennych referencyjnych (niezależnie od typu) jest taki sam i wynosi 4 bajty (jako typ int). Ale! Jeśli Twoja aplikacja działa na 64-bitowej maszynie Java, wszystkie odwołania będą miały rozmiar 8 bajtów (64 bity).

Linki mogą być przypisane tylko do siebie. Nie możesz zmieniać referencji ani przypisywać im dowolnych wartości:

Kod Opis
String hello = "Cześć";
String s = hello;
Więc możesz
String hello = "Cześć";
hello++;
A tak to niemożliwe
String hello = 0x1234;
I tak jest to niemożliwe

4. Pusty link -null

A co przechowuje zmienna referencyjna, jeśli nic nie zostało jeszcze do niej przypisane?

I przechowuje puste odwołanie - null . nullto specjalne słowo kluczowe w Javie, które oznacza brak referencji (puste referencje). Wartość nullmożna przypisać dowolnej zmiennej referencyjnej.

Wszystkie zmienne referencyjne, o ile nie przypisano im odniesienia, mają wartość null.

Przykłady:

Kod Opis
class Person
{
   public static String name;
   public static int age;
}


Zmienna String namema domyślną wartość: null.
Zmienna int agema domyślną wartość: 0.

Zmienne lokalne bez wartości są uważane za niezainicjowane zarówno dla typów pierwotnych, jak i typów referencyjnych.

Jeśli zmienna zawiera odniesienie do jakiegoś obiektu i chcesz wymazać wartość zmiennej, po prostu nadaj jej odniesienie zerowe.

Kod Opis
String s = null;
s = "Cześć";
s = null;
sprzechowuje łącze null.
sprzechowuje odniesienie do obiektu łańcuchowego
sprzechowuje odniesienienull

5. Przekazywanie referencji do metod

Jeśli jakakolwiek metoda ma jako parametry zmienne referencyjne , przekazanie do nich wartości jest dokładnie takie samo, jak podczas pracy ze zwykłymi zmiennymi. Zmiennej parametru po prostu przypisuje się wartość innej zmiennej.

Przykład:

Kod Opis
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");
   }
}


Metoda fillwypełnia przekazaną tablicę arrayprzekazaną wartością value.

Gdy metoda jest wywoływana, do fillzmiennej arrayprzypisywana jest referencja do tablicy data. Zmiennej valueprzypisywana jest referencja do obiektu łańcuchowego „Hello”.

Oto jak wyglądałaby sytuacja w pamięci przed wywołaniem metody fill :

Przekazywanie odwołań do metod

Oto jak będzie wyglądać sytuacja podczas działania metody fill :

Przekazywanie referencji do metod 2

Zmienne datai arrayreferencje (przechowuj referencje) do tej samej tablicy kontenerów w pamięci.

Zmienna valueprzechowuje odwołanie do obiektu typu string Hello.

Komórki tablicowe przechowują również tylko odwołania do obiektów Hello.

W rzeczywistości nie dochodzi do powielania obiektów - kopiowane są tylko łącza.



6. Porównanie z C/C++

Czasami programiści Javy są pytani podczas wywiadu: W jaki sposób dane są przekazywane do metod w Javie? Czasami też wyjaśniają: przez odniesienie czy przez wartość?

To pytanie pochodzi z języka C++ - nie ma sensu w języku Java . W Javie zmiennym parametru zawsze po prostu przypisuje się wartości zmiennych argumentów. Tak więc poprawną odpowiedzią byłoby - według wartości .

Ale bądź przygotowany na wyjaśnienie swojego stanowiska , ponieważ. możesz natychmiast zarzucić, że „typy pierwotne są przekazywane przez wartość, a typy referencyjne są przekazywane przez referencję”.

Źródła tego problemu wynikają z faktu, że wielu programistów Javy było w przeszłości programistami C++. I tam pytanie „w jaki sposób parametry są przekazywane do metod” odegrało bardzo ważną rolę.

W Javie wszystko jest jednoznaczne: typy pierwotne przechowują wartości, typy referencyjne również przechowują wartość - referencję. Chodzi o to, co należy uważać za wartość zmiennej.

W C++ zmienna może przechowywać zarówno odwołanie do obiektu, jak i sam obiekt. To samo dotyczyło typów pierwotnych: można było przechowywać wartość w zmiennej lub zadeklarować zmienną jako odwołanie do typu int. Dlatego, aby się nie pomylić, programiści C++ zawsze nazywają referencję do obiektu referencją , a sam obiekt jest zawsze nazywany wartością.

W C++ łatwo może się zdarzyć, że jedna zmienna zawiera obiekt, a druga referencję do tego samego obiektu. Dlatego pytanie o to, co przechowuje w sobie zmienna – sam obiekt, czy tylko odniesienie do niego – było bardzo ważne. Po przekazaniu do metody obiektowej została skopiowana (jeśli została przekazana przez wartość), a nie skopiowana (jeśli została przekazana przez referencję).

Java nie ma tej dwoistości, a poprawna odpowiedź brzmi: parametry do metod Java są przekazywane przez wartość . Tyle, że w przypadku zmiennych referencyjnych ta wartość jest referencją.