CodeGym /Kursy /JAVA 25 SELF /Przekazywanie parametrów przez wartość i przez referencję...

Przekazywanie parametrów przez wartość i przez referencję

JAVA 25 SELF
Poziom 8, Lekcja 4
Dostępny

1. Wprowadzenie

W różnych językach programowania istnieją dwa podstawowe sposoby przekazywania parametrów do funkcji (lub metod):

  • Przez wartość: funkcja otrzymuje kopię wartości zmiennej. Jeśli funkcja zmienia parametr, oryginał się nie zmienia.
  • Przez referencję: funkcja otrzymuje „referencję” (wskaźnik) do oryginalnego obiektu. Zmiany wewnątrz funkcji wpływają na oryginał.

W Java WSZYSTKIE parametry są przekazywane przez wartość!
Ale jest tu haczyk: gdy przekazujemy typy prymitywne (int, double, boolean itd.), kopiowana jest sama wartość. A gdy przekazujemy typy referencyjne (np. tablice lub obiekty), kopiowana jest wartość referencji (czyli „adres” obiektu w pamięci), a nie sam obiekt.

Jeśli czujesz, że mózg zaczyna się topić, spokojnie — za chwilę wszystko uporządkujemy i pokażemy na przykładach!

2. Typy prymitywne: kopiowana jest wartość

Zacznijmy od prostego przypadku: co się stanie, jeśli spróbujemy zmienić wartość zmiennej typu int wewnątrz metody?

public class Demo 
{
    public static void main(String[] args) 
    {
        int number = 5;
        changeValue(number);
        System.out.println(number); // Co zostanie wypisane?
    }

    public static void changeValue(int n) 
    {
        n = 42;
    }
}

Wynik: na ekran trafi 5.

Dlaczego?
Do metody changeValue przekazywana jest KOPIA wartości zmiennej number. Wewnątrz metody zmieniamy tylko kopię (n), a oryginalna zmienna number w main pozostaje nienaruszona.

Analogia
Wyobraź sobie, że dałeś koledze kserokopię paszportu, a nie oryginał. Kolega może rysować wąsy na kopii ile chce — twój prawdziwy paszport pozostanie bez zmian!

3. Typy referencyjne: kopiowana jest referencja

Teraz spróbujmy tego samego z tablicą:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        changeFirst(numbers);
        System.out.println(numbers[0]); // Co zostanie wypisane?
    }

    public static void changeFirst(int[] arr) 
    {
        arr[0] = 99;
    }
}

Wynik: na ekran trafi 99.

Dlaczego?
Do metody changeFirst przekazywana jest kopia REFERENCJI do tablicy numbers. Obie nazwy (numbers w main i arr w metodzie) wskazują na tę samą tablicę w pamięci. Dlatego jeśli zmienimy element tablicy wewnątrz metody, zmiana jest „widoczna” na zewnątrz.

Wizualizacja

main: numbers ──► [1, 2, 3]
                   ▲
                   │
changeFirst: arr ──┘
Kopia referencji wskazuje na ten sam obiekt w pamięci

Zmieniając arr[0], w rzeczywistości zmieniamy numbers[0], ponieważ oba wskazują na ten sam obiekt.

4. Ale jeśli zmienisz samą referencję — obiekt źródłowy się nie zmieni!

Spróbujmy teraz zrobić tak:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        replaceArray(numbers);
        System.out.println(numbers[0]); // Co zostanie wypisane?
    }

    public static void replaceArray(int[] arr) 
    {
        arr = new int[] {10, 20, 30};
    }
}

Wynik: wypisze 1.

Dlaczego?
W metodzie replaceArray zmienna arr zaczyna wskazywać na nową tablicę, ale nie wpływa to w żaden sposób na zmienną numbers w main.
Były powiązane jedną referencją, lecz gdy wewnątrz metody przypisujemy arr = ..., jest to tylko lokalna zmiana.

Analogia
To tak, jakbyś ty i twój znajomy mieli ten sam klucz do mieszkania. Znajomy dorobił sobie nowy klucz, ale twój stary klucz pozostał taki sam, a drzwi są te same.

5. Przykłady na utrwalenie: nie da się „zamienić miejscami” dwóch int przez metodę

Wielu początkujących próbuje napisać metodę zamieniającą miejscami dwie liczby, ale im się to nie udaje:

public class Demo 
{
    public static void main(String[] args) 
    {
        int a = 5, b = 10;
        swap(a, b);
        System.out.println(a + " " + b); // Oczekiwanie: 10 5, a w rzeczywistości?
    }

    public static void swap(int x, int y) 
    {
        int temp = x;
        x = y;
        y = temp;
    }
}

Wynik: na ekran trafi 5 10.

Dlaczego?
Ponieważ do swap trafiają kopie zmiennych a i b. Wszystko, co robimy wewnątrz swap, dotyczy tylko tych kopii, a nie oryginałów.

6. Ale w przypadku tablic można zmieniać zawartość!

Spójrzmy na poprawny sposób zamiany wartości w tablicy:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] arr = {5, 10};
        swap(arr);
        System.out.println(arr[0] + " " + arr[1]); // Oczekiwanie: 10 5
    }

    public static void swap(int[] arr) 
    {
        int temp = arr[0];
        arr[0] = arr[1];
        arr[1] = temp;
    }
}

Wynik: wypisze 10 5.

Dlaczego?
Ponieważ zmieniamy zawartość obiektu (tablicy), na który wskazuje zarówno oryginalna zmienna, jak i parametr metody.

7. Demonstracja: obiekty i ich pola

Z tablicami już jasne. A co z obiektami własnych klas? Dokładnie tak samo!

class Box 
{
    int value;
}

public class Demo
{
    public static void main(String[] args) 
    {
        Box box = new Box();
        box.value = 7;
        changeBox(box);
        System.out.println(box.value); // Co zostanie wypisane?
    }

    public static void changeBox(Box b) 
    {
        b.value = 42;
    }
}

Wynik: wypisze 42.

Dlaczego?
Ponieważ zmieniamy pole obiektu, na który wskazuje referencja.

Co dzieje się przy przekazywaniu parametrów do metod

Co przekazujemy Jak jest kopiowane Czy można zmienić wewnątrz metody? Czy zmiany są widoczne na zewnątrz?
int, double i in. Kopia wartości Tak, ale tylko kopię Nie
Tablica Kopia referencji Tak, jeśli zmieniasz elementy Tak
Obiekt (klasa) Kopia referencji Tak, jeśli zmieniasz pola Tak
Tablica/obiekt Kopia referencji Nie, jeśli przypiszesz nową referencję Nie

8. Typowe błędy

Błąd nr 1: oczekiwanie, że int zmieni się po wywołaniu metody. Wielu początkujących sądzi, że jeśli przekaże do metody zmienną typu int, to można zmienić jej wartość wewnątrz metody. To nieprawda: zmienia się tylko kopia!

Błąd nr 2: próba zamiany miejscami dwóch int przez metodę. Jak już widzieliśmy, to niemożliwe — zamieniają się tylko kopie zmiennych, oryginały pozostają nietknięte.

Błąd nr 3: próba „podmiany” tablicy przez metodę. Jeśli wewnątrz metody przypiszesz parametrowi-tablicy nową tablicę (arr = new int[]{...}), nie wpłynie to na oryginalną tablicę. Aby „podmienić” tablicę — trzeba zwrócić nową tablicę z metody i przypisać ją zmiennej w kodzie wywołującym.

Błąd nr 4: zapominanie, że można zmieniać zawartość obiektu. Jeśli przekazujesz obiekt (lub tablicę) — pamiętaj, że wszelkie zmiany jego pól/elementów będą widoczne na zewnątrz!

Błąd nr 5: zamieszanie z null. Jeśli przekażesz do metody referencję równą null i spróbujesz odwołać się do jej pól — otrzymasz NullPointerException. Bądź ostrożny!

1
Zadanie
JAVA 25 SELF, poziom 8, lekcja 4
Niedostępne
Reset punktu startowego robota na trajektorii 🤖
Reset punktu startowego robota na trajektorii 🤖
1
Zadanie
JAVA 25 SELF, poziom 8, lekcja 4
Niedostępne
Próba zaktualizowania listy bonusów gracza 🎁
Próba zaktualizowania listy bonusów gracza 🎁
1
Zadanie
JAVA 25 SELF, poziom 8, lekcja 4
Niedostępne
Zamiana zawodników w drużynie piłkarskiej ⚽
Zamiana zawodników w drużynie piłkarskiej ⚽
1
Zadanie
JAVA 25 SELF, poziom 8, lekcja 4
Niedostępne
Aktualizacja zawartości magicznej szkatułki 📦
Aktualizacja zawartości magicznej szkatułki 📦
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION